我做了一个可复制的代码如下/
#include <stdio.h> int main(void) { long int a = 0x0; a |= (1 << 31); printf("a: 0x%lx\n", a); }
我希望'a'应该是0x 000000080000000。但其值为a:0xffffffff80000000。为什么高32位以编程方式填充1,如果我想让'a'作为单个1和所有0值,我该怎么做?
sbdsn5lh1#
1是一个signed int。当你把它左移31位时,你会得到一个负数INT_MIN(假设32位整数和2是合格的)。然后当你把它赋值给long int(假设64位)时,它被符号扩展为具有相同的负值。它是C标准未定义的行为,但大多数现代计算机都有算术移位指令,并使用二进制补码编码。你需要使用一个无符号数:
1
signed int
INT_MIN
long int
int main(void) { long int a = 0x0; a |= (1U << 31); printf("a: 0x%016lx\n", a); }
https://godbolt.org/z/G95GYffPM或者你需要在二进制或之前将其转换为unsigned int。
unsigned int
int main(void) { long int a = 0x0; a |= (unsigned int)(1 << 31); printf("a: 0x%016lx\n", a); }
https://godbolt.org/z/bq3j4dWsc
13z8s7eq2#
来自C标准(6.5.7按位移位运算符)3对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。因此,此语句中使用的表达式( a << 31 )的类型
( a << 31 )
a |= (1 << 31);
是有符号整数类型int。进一步(相同的C标准部分)4 E1〈〈E2的结果是E1左移的E2比特位置;如果E1是无符号类型,则结果的值是E1 × 2 E2,比结果类型中可表示的最大值大1。如果E1是有符号类型和非负值,并且E1 × 2 E2在结果类型中可表示,则这是结果值;否则,行为未定义。假设一个int类型的对象包含32位,并且最高有效位是符号位,那么表达式(1 << 31 )的值在int类型的对象中是不可表示的,因此表达式调用未定义的行为。您至少需要使用无符号整数类型unsigned int,例如
int
32
(1 << 31 )
a |= (1u << 31);
无符号long int
a |= (1lu << 31);
请注意,结果取决于类型long int的大小。它可以等于4作为类型int的大小,也可以等于8作为类型long long int的大小。而不是在调用printf的格式字符串中手动写入0x
4
8
long long int
printf
0x
printf("a: 0x%lx\n", a);
您可以使用标记#,如
#
printf("a: %0#16lx\n", a);
j2qf4p5b3#
变更
到
a |= (1UL << 31);
1是一个int常数,它等于signed int。
3条答案
按热度按时间sbdsn5lh1#
1
是一个signed int
。当你把它左移31位时,你会得到一个负数INT_MIN
(假设32位整数和2是合格的)。然后当你把它赋值给long int
(假设64位)时,它被符号扩展为具有相同的负值。它是C标准未定义的行为,但大多数现代计算机都有算术移位指令,并使用二进制补码编码。
你需要使用一个无符号数:
https://godbolt.org/z/G95GYffPM
或者你需要在二进制或之前将其转换为
unsigned int
。https://godbolt.org/z/bq3j4dWsc
13z8s7eq2#
来自C标准(6.5.7按位移位运算符)
3对每个操作数执行整数提升。结果的类型是提升的左操作数的类型。
因此,此语句中使用的表达式
( a << 31 )
的类型是有符号整数类型
int
。进一步(相同的C标准部分)
4 E1〈〈E2的结果是E1左移的E2比特位置;如果E1是无符号类型,则结果的值是E1 × 2 E2,比结果类型中可表示的最大值大1。如果E1是有符号类型和非负值,并且E1 × 2 E2在结果类型中可表示,则这是结果值;否则,行为未定义。
假设一个
int
类型的对象包含32
位,并且最高有效位是符号位,那么表达式(1 << 31 )
的值在int
类型的对象中是不可表示的,因此表达式调用未定义的行为。您至少需要使用无符号整数类型
unsigned int
,例如无符号long int
请注意,结果取决于类型
long int
的大小。它可以等于4
作为类型int
的大小,也可以等于8
作为类型long long int
的大小。而不是在调用
printf
的格式字符串中手动写入0x
您可以使用标记
#
,如j2qf4p5b3#
变更
到
1
是一个int
常数,它等于signed int
。