我在玩C中的位操作,我不明白一件事,如果我有char b = 0x6c
,然后我有short y = 0x0000
,然后我做y=b; y = y << 12;
,为什么它用'f'
填充我的y
?
(编者注:>>
和<<
的方向很重要)
#include <stdio.h>
#include <stdlib.h>
int main()
{
short x = 0x0000;
short y = 0x0000;
char a = 0x00;
char b = 0x00;
char c = 0x00;
a = 'a'; /// 61
b = 'l'; /// 6c
c = 'b'; /// 62
x = a;
x = x<<8;
y = b;
x = x + b;
x = x >> 4;
x = x << 4;
y = y << 12;
printf(" x + temp = %#06x y = %#06x\n", x, y);
return 0;
}
3条答案
按热度按时间kdfy810k1#
在具有16位
int
的系统上,y << 12
导致未定义的行为,因为y
具有带符号类型,并且0x 6C 000太大而无法放入int
。在具有32位(或更大)
int
和16位short
的系统上,y = y << 12
结果由实现定义,或引发实现定义的信号。第二段可能适用于你。
同样,
%x
需要unsigned int
,而不是short
,因此printf
也会导致未定义的行为。因此,程序表现出实现定义和/或未定义的行为。
固定:
Demo(位于编译器资源管理器上)。
bmvo0sr52#
作为对前面优秀的answer的补充,我将使用一个不调用未定义行为的示例来解释发生了什么,该示例具有相同的行为。
结果:
x
具有值0x6c
,当左移12位时,其变为0xc000
。1.分配给有符号短整型(二进制补码系统)的
0xc000
为-16384
-16384
的二进制补码32位整数是0xffffc000
,这就是您看到此数字的原因7y4bm7vi3#
如果我有字符B = 0x 6c,然后我有短的y = 0x 0000,我做y=b;y = y〉〉12;,为什么我的y里都是“f”?
假设...
...然后存储在
y
中的值是0x6c
。需要类型short
才能表示该值。int
可以表示它 *,那么y << 12
的结果就被很好地定义为 *anint
*,值为0x6c000
。Cint
s可以窄到16位,这是不够的,但是现在大多数实现提供32位int
s,这是足够的。然而,很少有实现提供超过16位的
short
,因此y
不太可能表示该结果。...具有实现定义的结果或导致引发实现定义的信号。这不是 un 定义的行为。注意2:对于
unsigned short
或任何其它无符号类型,要求将是不同的。这种赋值的典型行为是存储最低有效的16位,而其他位丢失,这将给予存储在
y
中的位模式0xc000
,作为16位二进制补码short
的值,该位模式表示负数(十进制-16384)。当你试图打印结果时,
short
值被隐式转换为相同值的int
表示。你的int
显然是32位宽,并且负二进制补码表示的值保持加宽需要用1而不是零填充额外的前导位。因此,传入的第三个参数......是具有以下位模式的
int
:0xffffc000
.现在我们遇到了一些未定义的行为。在
printf
中,与%x
转换说明符匹配的参数值必须是unsigned int
,但实际传递的值是(signed
)int
。printf
参数之间的这种不匹配会产生未定义的行为。但是,在这种特定类型的int
/unsigned int
不匹配中,未定义行为的通常表现形式是int
位模式被解释为unsigned int
位模式。您报告的输出与这种表现形式一致。那么你应该怎么做呢?首先,在进行移位和位操作时,你通常应该使用无符号数据类型。其次,你应该注意(最小)宽度,并确保使用的类型宽度足以满足您的目的。如果您
#include <stdint.h>
,则(很可能)将能够使用类型uint16_t
,这是一个无符号整数数据类型,正好有16位,全部是值位。但是,这确实使您的printf
调用复杂化。或者,您可以使用unsigned short
,一个至少有16个值位的无符号整数类型,并且屏蔽掉除最低有效16位之外的所有位,或者甚至假设您的unsigned short
正好有16个值位--这一点得到了广泛的应用,尽管不是普遍的。