问题
昨天在写代码的过程中,遇到了这样一个东西:
用一个signed char类型的变量读取一个16进制数0xFF,然后再将其用printf输出成%02x的形式,最后的输出结果是:FFFFFFFF
DEMO程序如下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
signed char temp = 0;
int t = 0xff; //unsigned int和signed int不影响结果
fp = fopen("test.data", "wb");
fwrite(&t, 1, 1, fp);
fclose(fp);
fp = fopen("test.data", "rb");
fscanf(fp, "%c", &temp);
fclose(fp);
printf("%02x\n", temp);
return 0;
}
如上程序,signed char型的变量temp以二进制形式读取数据0xff,然后用printf以十六进制形式输出,最后输出了0xffffffff。
分析原因
首先signed char型是8位,temp以二进制形式读取0xff,由于其是有符号数,所以其是一个负数(-1)。然后到printf中以十六进制输出,由于printf中的格式化字符串%x要求输出数据类型为无符号16进制整数,且%x对应数据类型为unsigned int,因此temp首先进行有符号扩展,从signed char(0xff即8位-1)到signed int(0xffffffff,即32位的-1),再做无符号扩展,从signed int到unsigned int(0xffffffff,即32位的无符号数ffffffff)。
以上的分析都可以根据printf的源码得到,点击到源码链接。
附:printf源码
/* -*- linux-c -*- ----------------------------------------
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
------------------------------------------------------- */
/*
* Oh, it's a waste of space, but oh-so-yummy for debugging. This
* version of printf() does not include 64-bit support. "Live with
* it."
*
*/
#include "boot.h"
static int skip_atoi(const char **s)
{
int i = 0;
while (isdigit(**s))
i = i * 10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SMALL 32 /* Must be 32 == 0x20 */
#define SPECIAL 64 /* 0x */
#define __do_div(n, base) ({ \