在为取消引用的4字节指针分配字节值时,我的应用程序中出现了错误:
uint8_t value = 5;
uint8_t myArray [4] = {1,2,3,4};
uint32_t *myPointer = &myArray[0];
*myPointer = value; // myArray is now {5,0,0,0}
//*(uint8_t*)myPointer = value; // works correctly, myArray: {5,2,3,4}
在我看来,这是一个非常讨厌,难以察觉的错误,即使所有警告都打开,编译过程中也不会出现警告。为什么编译器没有处理这个问题,因为value
的大小是显而易见的?此外,我虽然指针大小的概念与指向更高地址的能力相关,而不是实际分配了多少内存。
答案 0 :(得分:4)
编译器会在您犯错时警告您:
uint32_t *myPointer = &myArray[0];
(...)
und.c:8:11: warning: incompatible pointer types initializing 'uint32_t *'
(aka 'unsigned int *') with an expression of type 'uint8_t *'
(aka 'unsigned char *') [-Wincompatible-pointer-types]
您选择将值重新解释为整数,这会导致未定义的行为。在此之后,您尝试重新解释第二次,忽略了您分配给整数的事实。但现在你陷入了C弱键入规则:你可以隐式地从uint8_t转换为uint32_t而不会发出警告。如果你想要它,C会做到。
答案 1 :(得分:3)
为什么编译器不处理这个
因为你得到你写的东西!
如果为32位存储分配值,则将访问32位存储。如果你说:
,那就是你写的uint32_t *myPointer
如果需要8位值,请使用指向8位值的指针!
编译器负责这一切!但是你不能将8位值写入指向32位值的指针。这导致从8位值转换为32位值!
uint8_t val;
uint32_t *myPointer;
*myPointer = val;
结果:
*myPointer = ( uint32_t ) val;
答案 2 :(得分:1)
赋值运算符分配给左侧,右侧的值。左侧的先前值被忽略。实际上它甚至都没有从内存中检索出来。
示例:
int a = 0x12345678;
a = 7;
cout << a << "\n"; // outputs 7
我不知道这是一个令人讨厌的错误&#34;一点都不。
如果你在谈论类类型,那么赋值运算符可能会被重载以保留左侧的部分原封不动(尽管这可能是一个糟糕的设计)。但对于原始类型,赋值甚至不检索分配给的内存位置的内容;它只写了新的内容。
如果右侧操作数的类型不匹配,则将其转换为左侧的类型。例如:
int a = 0x12345678;
double d = 6.5;
a = d;
cout << a << "\n"; // outputs 6
我不确定在这种情况下你应该输出什么。
在某些编程语言中,没有隐式转换,您必须编写a = (int)d;
。
无论好坏,C和C ++都不属于这些语言;并且您可以隐式地在算术类型之间进行转换。有些编译器会对潜在的缩小转换率发出警告,但没有人会警告&#34;扩大转换次数&#34;。
答案 3 :(得分:0)
这是值如何存储在内存中以及隐式转换发生的结果。概率为99.9%,您使用的是小型字节序处理器,如Intel或ARM,这意味着多字节类型的字节(如32位整数)以相反的顺序存储。如何存储32位int是相关的,因为8位value
在分配给*myPointer
(32位整数)时被隐式转换为32位int。当整数5存储在小端处理器上时,它会反转字节顺序。因此,最低有效字节5存储在myArray[0]
中,而更高有效字节0被分配给myArray[1]
,myArray[2]
和myArray[3]
。