为什么此代码打印10 = -246而不是10 = 10?指针大小是否重要?
#include <stdio.h>
int main() {
int i = 10;
int j = -1;
char *p, *q;
p = (char*) &i;
q = (char*) &j;
*q = *p;
printf("%d = %d\n", i, j);
return 0;
}
答案 0 :(得分:1)
首先,此处的结果取决于CPU的endianess。你似乎有一个小端CPU。
假设int
是32位2的补码,-1
以0xFFFFFFFF
的形式存储在4个字节中。 char
访问仅影响一个字节。由于你有小端,它将是你的情况下最不重要的字节。该字节将被值10,0x0A覆盖。最终得到0xFFFFFF0A
,它是-246的2的补码表示。
请注意char
类型具有实现定义的签名,因此在进行位/字节操作时应始终避免使用。请改用uint8_t
。
另请注意,在特定情况下使用字符类型(uint8_t是字符类型)时,通过不同类型的指针访问一种数据类型是有风险且定义不明确的,因为它们是“严格的别名规则“。
答案 1 :(得分:1)
指针大小是否重要?
不,指针的大小无关紧要。什么是指针的类型,即它指向的类型。
通过指针分配时复制的字节数取决于指针类型。如果指针类型是char指针,它将复制sizeof(char)
个字节。如果指针类型是int指针,它将复制sizeof(int)
个字节。
为什么此代码打印10 = -246而不是10 = 10?
它取决于系统。由于得到这个结果,你可能在一个小端系统上,这意味着内存中的数据首先以LSB存储(即指向变量的指针指向该变量的LSB)。
那么代码中发生的是变量i
的LSB被复制到变量j
的LSB。由于sizeof(int)
超过1,因此您不会在i
和j
相等的情况下结束。仅仅因为您没有将i
的所有字节都复制到j
。
假设32位int
,它可能看起来像:
答案 2 :(得分:0)
假设CPU为32位。
第一个问题:为什么要打印10 = -246
i = 10; (0x0000 000A)
j = -1; (0xFFFF FFFF) Two's Complement
* q指向整数j的最低8位,在*q = 10;
之后,j变为0xFFFF FF0A
,这是-246
参考How Computers Represent Negative Binary Numbers?
第二个问题:指针大小是否重要?
是的,在这种情况下,指向char指针的covert int指针将丢失24位数据。
答案 3 :(得分:0)
这里p&amp; q是一个char指针。 p =(char *)&amp; i;所以p将指向整数var i的第一个字节,它是4个字节。所以在解除p时你会得到10(00001010)。
q =(char *)&amp; j;当j = -1时,它是最大的负数。这意味着j var将在32位中全部为1(11111111 11111111 11111111 11111111)
* q = * p;在这一行中,您将最低的第一个字节(00001010)从i的位置复制到j的位置第一个字节,因为两个指针都是char *。所以现在复制后,j的位置值将为: 11111111 11111111 11111111 00001010相当于-246。计算11111111 11111111 11111111 00001010的2的补码。它会给你-246。
答案 4 :(得分:0)
您必须进行这样的转换才能使j中的i值为:
* (int*)p = * (int*)q
它将转换指针的类型,您将“转移” i在j中的值。
或者另外,您也可以不使用for循环而进行强制转换: `
for(int k=0; k<sizeof(int);k++){
*(p+k) = *(q+k);
}
` 通过此循环,您将一次将k的每个字节中的i的每一位写入一个字节。这是因为int具有4字节结构,而char具有1字节结构。