c - 为什么 printf ("%d", ~a); 当 a 等于 3 时显示 -4?
问题描述
运行以下程序显示 -4 而预期为 252:
unsigned char a=3;
printf ("%d", ~a);
为什么这段代码不显示 252?
我还根据建议的答案测试了以下内容:
printf ("%u", ~a);
显示:4294967292
printf ("%hu", ~a);
显示:65532
为什么~a
不返回一个,unsigned char
因为 a是一个unsigned char
?
我的问题不是我应该怎么做才能显示 252 ?我的问题是为什么不显示 252?
解决方案
除了@Someprogrammerdude 的回答,以下是 The Book 1)中的相关段落:
一元算术运算符(§6.5.3.3/4)
~运算符的结果是其(提升的 [ !! ] )操作数的按位补码(即,当且仅当未设置转换操作数中的相应位时,结果中的每个位都被设置)。整数提升在操作数上执行,结果具有提升的类型。如果提升的类型是无符号类型,则表达式~E等价于该类型中可表示的最大值减去E。
算术操作数 - 布尔值、字符和整数(第 6.3.1.1 节):
每个整数类型都有一个整数转换等级,定义如下:
- 任何两个有符号整数类型都不应具有相同的等级,即使它们具有相同的表示。
- 有符号整数类型的秩应大于任何精度较低的有符号整数类型的秩。
- long long int的等级要大于 long int 的等级,long int的等级要大于int的等级,要大于short int的等级,要大于signed char的等级。
- 任何无符号整数类型的等级应等于相应的有符号整数类型的等级,如果有的话。
- 任何标准整数类型的秩都应大于任何具有相同宽度的扩展整数类型的秩。
- char的等级应等于signed char和unsigned char的等级。
- _Bool的等级应小于所有其他标准整数类型的等级。
- 任何枚举类型的等级应等于兼容整数类型的等级(见 6.7.2.2)。
- 任何扩展有符号整数类型相对于另一个具有相同精度的扩展有符号整数类型的等级是实现定义的,但仍受用于确定整数转换等级的其他规则的约束。
- 对于所有整数类型T1、T2和T3,如果T1的秩大于T2且T2的秩大于T3,则T1的秩大于T3。
可以在可以使用int或unsigned int的表达式中使用以下内容:
- 具有整数类型的对象或表达式,其整数转换等级小于或等于int和unsigned int的等级。
- _Bool、int、signed int或unsigned int类型的位域。如果int可以表示原始类型的所有值,则将该值转换为int;否则,它将转换为unsigned int。这些被称为整数促销。48)整数提升不会改变所有其他类型。
- 整数促销保留价值,包括符号。如前所述,“普通”字符是否被视为有符号是实现定义的。
48) 整数提升仅适用于:作为通常算术转换的一部分,适用于某些参数表达式,适用于一元+、-和~运算符的操作数,以及移位运算符的两个操作数,由它们各自指定子条款。
你的问题:
为什么
~a
不返回一个unsigned char
因为a
是一个unsigned char
?
因为整数促销适用。
unsigned char a = 3; printf ("%d", ~a);
a
是一个unsigned char
,一个范围可以用一个来表示的类型int
。所以a
晋升为int
. 假设 32 位宽int
s 和二进制补码:
3 10 = 0000 0000 0000 0000 0000 0000 0000 0011
2
~3 10 = 1111 1111 1111 1111 1111 1111 1111 1100
2
结果解释为signed int
负数,因为设置了最高有效位,即符号位。
转换为十进制:
1111 1111 1111 1111 1111 1111 1111 1100
2
¬ 0000 0000 0000 0000 0000 0000 0000 0011
2
+ 0000 0000 0000 0000 0000 0000 0000 0001
2
──────────────────────────
0000 0000 0000 0000 0000 0000 0000 0100
2
0100 2 = 0 × 2 3 + 1 × 2 2 + 0 × 2 2 + 0 × 2 2
= 1 × 2 2
= 4 10
= -4 10(带原符号)
~>printf()
打印-4
。
"%d"
要使用用作格式说明符的原始代码获得所需的 252 结果,需要进行一些转换:
unsigned char a = 3;
printf("%d\n", (int)((unsigned char) ~a)); // prints 252
// ^^^ ^^^^^^^^^^^^^
// | cast the result of ~a back to unsigned char *)
// | to discard the bits > CHAR_BIT
// cast the char back to int to agree with the format specifier
*)感谢 chux 让我记得这char
可能是signed
!强制转换为 (可能signed
)char
会给出错误的结果 -4。
要在不进行强制转换的情况下获得相同的结果,可以使用长度修饰符hh
:
fprintf 函数 (§7.19.6.1/7)
长度修饰符及其含义是:
hh 指定后面的d、i、o、u、x或X转换说明符适用于有符号字符或无符号字符参数(该参数将根据整数提升进行提升,但其值应在打印前转换为有符号字符或无符号字符);或者后面的n转换说明符适用于指向有符号字符参数的指针。
[...]
unsigned char a = 3;
printf("%hhu\n", ~a); // prints 252
您其他尝试的问题:
printf ("%u", ~a);
显示:4294967292
printf ("%hu", ~a);
显示:65532
由于~a
是一个int
eger,它不是格式说明符的正确类型,u
并且
fprintf 函数(§7.19.6.1/9):
如果转换规范无效,则行为未定义。248) 如果任何参数不是相应转换规范的正确类型,则行为未定义。
1) ISO/IEC 9899/Cor3:2007 又名 C99:TR3 又名 C99
推荐阅读
- python - Imblearn SMOTE:如何为多类不平衡数据集设置 sample_strategy 参数?
- python - Pythinic spark 作业正在尝试从某个地址获取某些内容并失败
- jmeter - Jmeter灵活文件写入头问题
- javascript - 在图像上插入文本并通过将鼠标悬停在 (JavaScript) 上来更改文本
- selenium - TestNG 不执行优先级较低的测试用例
- opencv - 在 EMGU CV 中使用 Contrib 模块
- python - 如何在 numpy 中使用多维索引访问值?
- javascript - 在终端中使用“npm install react-native-modal-datetime-picker”时出错
- model-view-controller - Kendo UI Jquery 动态网格与动态数据源
- sql - 每次按下刷新按钮时DataGridView都会重复vb.net