San*_*sj5 57 c variables types bitwise-operators unsigned-char
我正在阅读关于按位运算符的章节,我遇到了1的补码运算符程序,并决定在Visual C++上运行它.
int main ()
{
unsigned char c = 4, d;
d = ~c;
printf("%d\n", d);
}
Run Code Online (Sandbox Code Playgroud)
它给出了有效的输出: 251
然后我决定直接打印值,而不是d用作变量来保存~c值~c.
int main ()
{
unsigned char c=4;
printf("%d\n", ~c);
}
Run Code Online (Sandbox Code Playgroud)
它给出了输出-5.
它为什么不起作用?
Grz*_*ski 55
在这个声明中:
printf("%d",~c);
Run Code Online (Sandbox Code Playgroud)
在应用(按位补码)运算符之前将c其转换为int1类型.这是因为整数提升,被调用到的操作数.在这种情况下,类型的对象被提升为(带符号),然后(在运算符评估之后)由函数使用,具有匹配的格式说明符. ~~unsigned charint~printf%d
请注意,默认参数提升(作为printf可变参数函数)在此处不起任何作用,因为对象已经是类型int.
另一方面,在这段代码中:
unsigned char c = 4, d;
d = ~c;
printf("%d", d);
Run Code Online (Sandbox Code Playgroud)
发生以下步骤:
c因为(以同样的方式,如上所述)是整数促销的主题~~crvalue被评估为(有符号)int值(例如-5)d=~c使得从隐式转换int到unsigned char,因为d具有这样的类型.你可能会认为它和它一样d = (unsigned char) ~c.请注意,d不能为负(这是所有无符号类型的一般规则).printf("%d", d);调用默认参数提升,因此d转换为int并保留(非负)值(即int类型可以表示所有unsigned char类型的值).1)假设它int可以代表所有的值unsigned char(参见下面的TC 评论),但很可能以这种方式发生.更具体地说,我们假设INT_MAX >= UCHAR_MAX持有.通常,sizeof(int) > sizeof(unsigned char)保持和字节由8位组成.否则c将转换为unsigned int(如C11子条款§6.3.1.1/ p2),格式说明符也应相应更改,%u以避免获得UB(C11§7.21.6.1/ p9).
hac*_*cks 27
char被提升到int在printf操作之前的语句~排在第二片段.那么c,这是
0000 0100 (2's complement)
Run Code Online (Sandbox Code Playgroud)
在二进制中被提升为(假设32位机器)
0000 0000 0000 0000 0000 0000 0000 0100 // Say it is x
Run Code Online (Sandbox Code Playgroud)
并且它的逐位补码等于值的二进制补码减去一(~x = ?x ? 1)
1111 1111 1111 1111 1111 1111 1111 1011
Run Code Online (Sandbox Code Playgroud)
这是-5二进制补码形式的十进制数.
请注意,也会执行 char c to 的默认促销int
d = ~c;
Run Code Online (Sandbox Code Playgroud)
补体操作之前但结果被转换回unsigned char为d是类型unsigned char.
在简单赋值(
=)中,右操作数的值将转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值.
和
赋值表达式的类型是左值操作数在左值转换后将具有的类型.
Gri*_*han 17
要理解代码的行为,你需要学习一个名为"整数促销"的概念(在操作unsigned char数上按位操作之前隐式地在代码中发生)如N1570委员会草案所述:
§6.5.3.3一元算术运算符
~运算符的结果是其(提升的)操作数的按位补码(也就是说,当且仅当未设置转换的操作数中的相应位时,才会设置结果中的每个位).整数提升在操作数上执行,结果具有提升类型.如果提升的类型是"'无符号类型',则表达式~E等于该类型中可表示的最大值减去E".
因为unsigned char类型比(因为它需要更少的字节)int类型更窄,所以- 抽象机器(编译器)执行的隐式类型提升和变量的值在编译时(在应用补充操作之前)c被提升.它是正确执行程序所必需的,因为需要一个整数操作数.int~~
§6.5表达式
- 一些运营商(一元运算符
~,和二进制运算符<<,>>,&,^,和|,统称为位运算符)都要求有具有整型操作数.这些运算符产生的值取决于整数的内部表示,并且具有已签名类型的实现定义和未定义方面.
编译器足够智能 - 足以分析表达式,检查表达式的语义,执行类型检查和算术转换(如果需要).这就是应用~on char类型的原因,我们不需要显式写~(int)c- 称为显式类型转换(并避免错误).
注意:
值c被提升到int表达式中~c,但类型c仍然是unsigned char- 它的类型不是.不要混淆.
重要:~操作的结果是int类型!,检查下面的代码(我没有vs-compiler,我使用的是gcc):
#include<stdio.h>
#include<stdlib.h>
int main(void){
unsigned char c = 4;
printf(" sizeof(int) = %zu,\n sizeof(unsigned char) = %zu",
sizeof(int),
sizeof(unsigned char));
printf("\n sizeof(~c) = %zu", sizeof(~c));
printf("\n");
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
编译它,然后运行:
$ gcc -std=gnu99 -Wall -pedantic x.c -o x
$ ./x
sizeof(int) = 4,
sizeof(unsigned char) = 1
sizeof(~c) = 4
Run Code Online (Sandbox Code Playgroud)
注意:结果的大小~c 相同int,但不等于unsigned char- ~表达式中运算符的结果是int!如上所述6.5.3.3一元算术运算符
- 一元运算
-符的结果是其(提升的)操作数的否定.整数提升在操作数上执行,结果具有提升类型.
现在,正如@haccks在他的回答中解释的那样- ~c32位机器的结果和价值c = 4是:
1111 1111 1111 1111 1111 1111 1111 1011
Run Code Online (Sandbox Code Playgroud)
十进制是-5- 这是你的第二个代码的输出!
在第一码,一个多线有趣的是理解b = ~c;,因为b是unsigned char可变的,并且结果~c就是的 int类型,所以,以适应的结果的值~c,以b产生值(〜c)的截短以适应unsigned char类型 如下:
1111 1111 1111 1111 1111 1111 1111 1011 // -5 & 0xFF
& 0000 0000 0000 0000 0000 0000 1111 1111 // - one byte
-------------------------------------------
1111 1011
Run Code Online (Sandbox Code Playgroud)
十进制当量1111 1011是251.使用以下方法可以获得相同的效
printf("\n ~c = %d", ~c & 0xFF);
Run Code Online (Sandbox Code Playgroud)
或者@ouah在他的回答中使用显式强制转换的建议.
alk*_*alk 12
当应用~运算符到c它被提升时int,结果也是int如此.
然后
unsigned char然后被提升signed int并打印出来.signed int.oua*_*uah 10
它给出了op -5.为什么它不起作用?
代替:
printf("%d",~c);
Run Code Online (Sandbox Code Playgroud)
使用:
printf("%d", (unsigned char) ~c);
Run Code Online (Sandbox Code Playgroud)
获得与第一个示例中相同的结果.
~ 操作数经过整数提升,默认参数提升应用于可变函数的参数.