我写了一段非常简单的C代码:
int main(void) {
void *area = malloc(2 * sizeof(int));
unsigned int *int_one = (unsigned int *) area;
unsigned int *int_two = ((unsigned int *) area) + 3;
*int_two = 4293422034;
*int_one = 2;
printf("%un%un", *int_two, *int_one);
return 0;
}
sizeof(int)
在我的机器上4
。根据我的理解,地址int_one
内存的修改不应该对地址int_two
存储的值产生影响吗?
修改*int_one
会更改 mem. 地址area
的前4
个字节(也许不是全部 4 个,但足以保证我期望的结果?(,地址int_two
处的整数从整数int_one
的最后一个字节开始。
那么,在int_one
改变记忆不应该对int_two
的记忆产生影响吗? 然而,printf
调用分别产生4293422034
和2
。
我确保使用无符号变量以避免混淆 2s 补码和负值,并为*int_one
使用一个小值来保证其最后一个字节的更改(不知道这是否正确?
我没有得到什么?
运算符"+"应用于指针时,会将指针增加n
倍于它指向的对象的大小。因此,将int*
增加3
不会增加 3 个字节,而是增加3*sizeof(int)
个字节。
指针算术按指针指向的类型大小进行缩放。(sizeof(unsigned int)
在您的情况下(。如果要将地址增加 3 个字节,则需要在添加 3 之前强制转换为(char*)
,但将其转换为unsigned*
指针会违反对齐要求 (6.3.2.3p7( 而导致未定义的行为,取消引用指针会使程序通过违反严格的别名规则 (6.5p7( 而"更加未定义"。
要真正正确地进行这种类型的双关语,您需要使用memcpy
(或union
s(。
例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
void *area = malloc(2 * sizeof(int));
if(!area) return EXIT_FAILURE;
unsigned int *int_one_p = area;
void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/
memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));
unsigned one,two;
memcpy(&one,int_one_p, sizeof(one));
memcpy(&two,int_two_p, sizeof(two));
printf("%un%un", two, one);
return 0;
}