现在有以下代码有什么问题?
int main(){
union {
char arr[10];
int var;
} u;
int *ptr_var= (int*) &(u.arr[1]);
*ptr_var = 42;
}
答案 0 :(得分:4)
注意:已经给出了正确答案,这只是解释背景的另一种方式。
访问内存中的对象时,大多数计算机都要求对齐对象。这意味着必须将四字节(32位)对象放置在可被四个分割的地址上。这源于CPU使用数据总线与存储器连接的事实,在我们的示例中总线是32位。如果CPU支持未对齐的访问,则必须请求对内存的两次访问并将它们拼接在一起。相反,大多数架构认为这是非法操作。
在您的情况下,您从一个联合开始,该联合存储在一个偶数四字节的地址。然后你向前走一个字节并尝试在一个地址上访问一个int
,该地址绝对不是该数量的偶数倍。
答案 1 :(得分:3)
你确定这是在给段错吗?标题是误导!!
旧架构上的AFAIK会导致总线错误。但正如this post所解释的那样,你最近没有看到公共汽车的错误。
这会导致总线错误,因为数组/ int联合确保字符数组arr
也处于一个合理对齐的地址,该整数&arr[1]
肯定不能正确对齐整数。然后,您尝试将sizeof(int)
个字节存储到仅与单字节访问对齐的地址中。 Arghh !!!
答案 2 :(得分:1)
这里编译很简单。没有分段错误。编译器的输出究竟是什么?
在这里你可以看到:
#include <stdio.h>
int main()
{
int *ptr_var;
union
{
char arr[10];
int var;
} u;
u.arr[0]='A';
u.arr[9]='\0';
ptr_var = (int*) &u.arr[1];
*ptr_var = 0x2a;
printf("%s\n", u.arr);
printf("%d(d)=%x(x)\n",u.var, u.var);
}
答案是:
cpp/test/temp$ gcc union.c -o union
cpp/test/temp$ ./union
A*
10817(d)=2a41(x)
cpp/test/temp$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
这是移动位的好方法。也许你的段错误在程序的另一个区域。见这个测试:
*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);
ptr_var = (int*) &u.arr[1];
*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);
ptr_var = (int*) &u.arr[2];
*ptr_var = 0x10;
printf("%d(d)=%x(x)\n",u.var, u.var);
你得到:
16(d)=10(x)
4112(d)=1010(x)
1052688(d)=101010(x)
保重, BECO。
答案 3 :(得分:0)
这取决于架构。我猜这个标准可能会再次说这个行为是“未定义的”。在不同平台上运行时,我得到的结果不同:
1&GT; Linux on X86:运行正常没有问题 2 - ; sparc上的Solaris:“总线错误(核心转储)”。