按位“;不是";C中的运算符返回带符号的结果
考虑以下代码:按位“;不是";C中的运算符返回带符号的结果,c,linux,gcc,gnu99,C,Linux,Gcc,Gnu99,考虑以下代码: uint16_t a = ~ ( uint16_t ) 0; int16_t b = ~ ( int16_t ) 0; printf ( "%d %d %d %d\n", a == ~ ( uint16_t ) 0, a == ( uint16_t ) ( ~ ( uint16_t ) 0 ), b == ~ ( int16_t ) 0, b == ( int16_t ) ( ~ ( int16_t ) 0 ) ); 输出为:
uint16_t a = ~ ( uint16_t ) 0;
int16_t b = ~ ( int16_t ) 0;
printf (
"%d %d %d %d\n",
a == ~ ( uint16_t ) 0,
a == ( uint16_t ) ( ~ ( uint16_t ) 0 ),
b == ~ ( int16_t ) 0,
b == ( int16_t ) ( ~ ( int16_t ) 0 )
);
输出为:
01
GCC抛出关于a==~(uint16\u t)0的警告:
由于数据类型[-Wtype limits]的范围有限,比较总是错误的
为什么按位“not”运算符试图返回有符号值?我怎样才能防止呢
为什么按位“not”运算符尝试返回有符号值
因为没有运算符处理小于int
的类型;较小的类型(包括uint16\u t
ifint
超过16位)在用作操作数时升级。如果原始类型的所有值都可以用int
表示,如此处所示,则升级为int
我怎样才能防止呢
你不能;这就是语言的工作原理。您必须将运算符的结果转换为所需的类型,要么像初始化a
时那样隐式转换,要么显式转换。请注意,在应用~
之前不需要强制转换;但为了实现最大的可移植性,在执行按位逻辑时,应坚持使用无符号类型:
uint16_t a = ~0u;
printf("%d\n", a == (uint16_t)~0u); // Should print 1
符号是一个位于位模式之上的概念。按位not(~)只涉及位模式,而不涉及值的符号。将有符号值notting为无符号值的结果是相同的
话虽如此,看看C标准:(草稿版免费提供)。第51页第6.3.1.4节:
如果一个int可以表示原始类型的所有值(受宽度限制,对于一个位字段),则该值将转换为int;否则,它将转换为无符号整数。这些称为整数。(58)所有其他类型不受整数的影响
我的意思是,当我们实际操作char和short类型时,它们将被提升为int(或unsigned int,取决于大小)。这是有意义的,因为我们希望操作尽可能快地完成,所以我们应该以机器的本机大小为目标
鉴于此,我们可以看到实际发生的情况。机器将以“int”大小执行所有操作,因为“==”和“~”的操作数都可以放入一个int字段中,我假设您的机器中的int字段为32位
现在首先要看的是‘a’的值。我们取0,而不是它,得到0xFFFFFFFF。我们将其分配给一个uint16_t值并得到0xFFFF。当我们准备好进行比较时,我们加载0xFFFF,意识到该值是无符号的,并将其扩展为0x0000FFFF。对于“b”的值,除了读取0xFFFF进行比较时,我们将其扩展到0xFFFFFF之外,所有内容都是相同的。现在,对于您的案例:
Notting零表示0xFFFFFF,与0x0000FFFF比较将失败
我们取0xFFFFFF,将其切碎为0xFFFF,然后零将其扩展为0x0000FFFF,得到与“a”相同的值
等等。波浪号~
运算符不是一元not。它是一个(一元)翻转所有位
逐位运算符。~
是一元的补码运算符。我现在知道这个运算符的作用=)。我不知道该如何命名这个操作符。维基百科说“按位'不'”@puchu~
是按位不,代码>不是布尔值…请阅读以下答案:这不清楚为什么printf
应该打印“1”。是否打算使用此处所示的表达式(uint16_t)~0
或原始代码中的表达式~(uint16_t)0
初始化a
?如果是后者,则不必打印“1”。后一个表达式总是在a
中生成65535,但前者的值可能为0、1或65535,具体取决于C实现。最好使用~0u
而不是~0
@EricPostpischil:当然,你是对的;很容易忘记,当我有生之年(或多或少)不存在有符号整数时,这种语言支持有符号整数的奇异表示。我已经添加了一个注释,未签名类型应该是首选的,以防有人在编写UNIVAC时盲目地遵循我的建议。