在C中,像-1这样的有符号整数应该用关键字signed
声明,如下所示:
signed int i = -1;
然而,我试过这个:
signed int i = -2;
unsigned int i = -2;
int i = -2;
并且所有3个案例都打印出-2 printf("%d", i);
。为什么呢?
答案 0 :(得分:3)
打印整数变量的方式受到传递给printf
的格式字符串的影响:
%d
,那么您将打印为有符号整数。%u
,那么您将打印为无符号整数。答案 1 :(得分:3)
由于您确认使用以下方式进行打印:
printf("%d", i);
这是未签名案例中的undefined behavior。 draft C99 standard部分7.19.6.1
fprintf函数中介绍了格式说明符的printf
,它在段落 9 中说明:
如果转换规范无效,则行为未定义。 248) [...]
第3.4.3
部分未定义的行为中定义的标准为:
行为,在使用不可移植或错误的程序结构或错误数据时, 本国际标准没有要求
并进一步说明:
可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的文档方式执行,终止翻译或执行(发布诊断信息)。
最后,我们可以看到 int 与 signed int 相同。我们可以通过转到6.7.2
类型说明符部分看到这一点,在段落 2 中将 int 分组如下:
int,signed或signed int
以及稍后在段落 5 中说:
除了bit-field [...]
之外,每个逗号分隔的集都指定相同的类型
答案 2 :(得分:1)
printf
无法知道你传递给它的是什么。 C编译器在传递参数时执行默认类型提升,然后函数本身根据您传递的格式说明符重新解释值,因为它没有关于值的类型的其他信息你通过了。
当您将unsigned int
传递给位居printf
的{{1}}时,它是未定义的行为。你的程序不正确,它可以打印任何东西。
在两个补码表示中代表负数的硬件上会出现与您开始时相同的数字。但是,这不是一个普遍规则。
答案 3 :(得分:0)
unsigned int i = -2; // i actually holds 4294967294
printf("%d", i); // printf casts i back to an int which is -2 hence the same output
答案 4 :(得分:0)
你有两件事情在继续:
您将有符号值(-2)传递给无符号变量,然后请求printf将其解释为已签名。
请记住,“签名”和“无符号”与如何对数字进行算术运算有关。 printf系列接受内部转换根据格式指示符传入的任何内容。 (这是可变函数的性质,它接受多种类型的参数。它们不能使用传统的类型安全机制)
这一切都很好,但并非所有事情都会起作用。
在大多数架构中,加法和减法的工作方式相同(只要你没有使用一些不使用2的补码表示负数的古怪架构) 乘法和除法也可以相同。 不平等比较是最难以了解它们将如何工作的事情,而且我已经多次对有符号和无符号进行比较,我认为这样做是正常的,因为它们处于小的有符号数范围内。
多数是“未定义”的含义。行为由编译器和硬件实现者完成,并且在架构之间甚至在同一架构上都不能相同。