我想打印b [FFFC]的值,如下所示,
short var = 0xFFFC;
printf("%d\n", b[var]);
但它实际上打印了b [FFFF FFFC]的值。
为什么会这样?
我的电脑由Windows XP以32位架构运行。
答案 0 :(得分:7)
short
是签名类型。它的实现是16位。 0xFFFC表示整数常量65,532,但转换为16位有符号值时,结果为-4。
因此,您的行short var = 0xFFFC;
将var设置为-4(在您的实现上)。
0xFFFFFFFC是-4的32位表示。所有发生的事情是您的值正在从一种类型转换为更大的类型,以便将其用作数组索引。它保留了它的值,即-4。
如果您确实想要访问数组的65,533rd元素,那么您应该:
var
使用更大的类型。 int
在32位Windows上就足够了,但总的来说size_t
是一个无符号类型,对于非负数组索引来说,它的保证足够大。unsigned short
,其中 为此示例提供足够的空间,但如果您想再向前迈进4步,则会出错。答案 1 :(得分:1)
在当前编译器中,如果写short
使用32位,则不能使用short
(16位)。
例如,我在Ubuntu Linux 32位中用gcc4编译相同的代码:
int main(int argc, char** argv)
{
short var = 0xFFFC;
printf("%x\n", var);
printf("%d\n", var);
return (EXIT_SUCCESS);
}
,输出为:
fffffffc
-4
你可以看到强制转换为32位正常,并在2的补码中使用符号扩展
答案 2 :(得分:1)
使用%hx 或%hd来表示您有一个短变量,例如:
printf("short hex: %hx\n", var); /* tell printf that var is short and print out as hex */
编辑:Uups,我的问题出错了。我认为这不是关于printf()的。所以这个答案可能有点OT。
新:因为您使用 var 作为数组的索引,所以您应该将其声明为 unsigned short (而不是short):
unsigned short var = 0xFFFC;
printf("%d\n", b[var]);
'short var'可以解释为负数。
更确切地说:
您正在“下溢”到负值范围:从0x0000到0x7FFF范围内的值将是正常的。但是从0x8000到0xFFFF的值将为负值。
以下是 var 的一些示例,用作数组b []的索引:
short var=0x0000;; // leads to b[0] => OK
short var=0x0001; // leads to b[1] => OK
short var=0x7FFF; // leads to b[32767] => OK
short var=0x8000; // leads to b[-32768] => Wrong
short var=0xFFFC; // leads to b[-4] => Wrong
short var=32767; // leads to the same as b[0x7FFF] => OK
short var=32768; // compile warning or error => overflow into 32bit range
答案 3 :(得分:1)
作为可用的C数据类型的复习,请查看here。 有一个规则,它涉及C的用法,一些数据类型被提升为它们的整数类型,例如
char ch = '2'; int j = ch + 1;
现在查看表达式的RHS(右侧)并注意ch
将自动升级为 int ,以便在LHS上产生所需的结果( LHS)的表达方式。 j
的价值是多少? '2'的ASCII码为50十进制或0x32十六进制,加1为1,j
的值为51十进制或0x33十六进制。
理解该规则很重要,这解释了为什么数据类型会“被提升”为另一种数据类型。
什么是b
?这是一个我认为655532元素正确的数组吗?
无论如何,使用格式说明符%d
的类型为int,值首先被提升为int,其次,数组下标的类型为int
,因此使用{ {1}}得到提升,因为int的数据大小是4个字节,所以它被提升了,因此你看到了剩余的值0xFFFF 0xFFFC。
这是使用 cast 的地方,告诉编译器将强制数据类型告诉另一个,这与Gregory Pakosz上面的答案一起解释。
希望这有帮助, 最好的祝福, 汤姆。
答案 4 :(得分:0)
你期望在32位对齐的内存中存储一个16位变量...你看,每个内存地址都有一个整个 32位字(硬件)。
额外的FFFF来自short是签名值的事实,当分配给 int (在printf调用时)时,它得到了签名扩展。当将两个补码从16位扩展到32位时,通过将最后N位复制到其左侧的所有其他M-N来完成扩展。当然,你并不打算这样做。
因此,在这种情况下,您对绝对数组位置感兴趣,因此您应该将索引器声明为 unsigned 。
答案 5 :(得分:0)
在您的问题的主题中,您已经猜到了这里发生了什么:是的,类型short
的值被“自动扩展”为类型int
的值。此过程称为整数提升。这就是它总是在C语言中工作的方式:每次使用小于int
的整数值时,该值总是被隐式提升为int
类型的值(无符号值可以提升为unsigned int
})。当然,值本身不会改变,只会改变值的类型。在上面的示例中,模式short
表示的16位0xFFFC
值与模式int
表示的32位0xFFFFFFFC
值相同,即{{1}小数点。这个,BTW,使你的问题的其余部分听起来很奇怪:促销与否,你的代码试图访问-4
。促销b[-4]
不会改变任何内容。