具有相同地址的C extern?
C编译器能否假定两个不同的外部全局变量不能被别名到相同的地址?具有相同地址的C extern?
在我的情况,我有这样的情况:
extern int array_of_int[], array_end; void some_func(void) { int *t; for (t = &array_of_int[0]; t != &array_end; t++) { ...
生成的二进制与优化编译在进入循环之前没有测试
t != &array_end条件。编译器的优化是循环必须至少执行一次,因为
t
一开始不能立即等于
&array_end
。
当然我们发现这很难。显然,一些带链接器部分的汇编器hackery导致两个extern是相同地址的情况。
感谢您的任何建议!
总之,是的,它可以自由地做出这个假设。 extern
变量没有什么特别之处。两个变量可能不是别人的别名。 (如果答案有任何不同,请考虑随后发生的混乱,extern int a, b
可能会互相混淆,这会使得使用这些变量的任何代码的语义完全疯狂!)
实际上,您正在依靠未定义行为在这里,句号。以这种方式比较无关变量的地址是无效的。
是的,这是未定义的行为。这是相当微妙的发现,所以[我发布了'固定'版本(http://stackoverflow.com/questions/5559281/c-externs-that-alias-the-same-address/5559351#5559351),这是很可能是@srking打算的内容 – sehe 2011-04-05 22:40:04
不等式比较不是未定义的,而是落在数组的末尾(因为'array_end'不能具有与其任何元素相同的地址)。如果循环体中的某些内容确保它在这种情况发生之前总是中断,那么此代码将是合法且可移植的。 – 2011-04-05 22:47:35
@Steve:你是对的。我一直在误解标准,直到现在! – 2011-04-05 22:55:18
我觉得这里是在另一个编译单元的固定码
#include <stdio.h>
extern int array_of_int[];
extern int *array_end;
int main()
{
int *t;
for (t = &array_of_int[0]; t != array_end; t++)
{
printf("%i\n", *t);
}
return 0;
}
:
int array_of_int[] = { }; // { 1,2,3,4 };
int *array_end = array_of_int + (sizeof(array_of_int)/sizeof(array_of_int[0]));
它编译成这个(-O3,GCC 4.4.5的i686)
080483f0 <main>:
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 83 e4 f0 and $0xfffffff0,%esp
80483f6: 53 push %ebx
80483f7: 83 ec 1c sub $0x1c,%esp
80483fa: 81 3d 24 a0 04 08 14 cmpl $0x804a014,0x804a024
8048401: a0 04 08
8048404: 74 2f je 8048435 <main+0x45>
8048406: bb 14 a0 04 08 mov $0x804a014,%ebx
804840b: 90 nop
804840c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi
8048410: 8b 03 mov (%ebx),%eax
8048412: 83 c3 04 add $0x4,%ebx
8048415: c7 44 24 04 00 85 04 movl $0x8048500,0x4(%esp)
804841c: 08
804841d: c7 04 24 01 00 00 00 movl $0x1,(%esp)
8048424: 89 44 24 08 mov %eax,0x8(%esp)
8048428: e8 d7 fe ff ff call 8048304 <[email protected]>
804842d: 39 1d 24 a0 04 08 cmp %ebx,0x804a024
8048433: 75 db jne 8048410 <main+0x20>
8048435: 83 c4 1c add $0x1c,%esp
8048438: 31 c0 xor %eax,%eax
804843a: 5b pop %ebx
804843b: 89 ec mov %ebp,%esp
804843d: 5d pop %ebp
804843e: c3 ret
804843f: 90 nop
没错,但这不是OP正在描述/询问的内容。 – 2011-04-05 22:38:17
点了,在循环条件发生了另一个奇怪的事情,我张贴我的修复代码 – sehe 2011-04-05 22:38:48
C99在6.2.2“标识符的长度”中说:
在不同 作用域或在多于一次 可以使由一个过程来指代相同的 对象或功能的相同范围声明的标识符称为 联动。 (脚注21)
...
脚注21:有不同的标识符之间没有联系 。
因此,不幸的是,这种有点常见的汇编语言技巧(我用过......)没有很好的定义。你最好让你的汇编模块定义array_end
作为asm代码加载数组结尾地址的实际指针。这样C代码可以很好地定义,因为array_end
指针将是一个单独的对象。
它的情况下,如果我们在ARM代码中做到这一点很简单 - 我们有一个属性,它..
#include <stdio.h>
int oldname = 1;
extern int newname __attribute__((alias("oldname"))); // declaration
void foo(void)
{
printf("newname = %d\n", newname); // prints 1
}
只有EXTERN就够了这里。 将其导入其他文件 - 其无缝。用于汇编文件的 - 您可以使用IMPORT命令,并且您有别名。 :)
啊哈,只有_now_我明白了。代码试图依赖包含array_of_int [] ...的对象文件的数据段中的数据布局,这是_is_脏。我发布了规范版本... – sehe 2011-04-05 22:43:01