使用extern指针声明外部函数的错误

时间:2016-07-13 04:15:29

标签: c assembly linker elf

根据我的理解,ELF目标文件中的符号只是内存地址的名称。换句话说,给定一个符号名称,无论在C中声明它们的类型,链接器都应始终引用相同的地址。

我发现事实并非如此。请参阅以下示例:

/* a.c */
extern void *foo;
extern void *bar;
void main() {
  printf("foo: %p, bar: %p\n", foo, bar)
}

/* b.c */
void foo(void) {
}
void bar(void) {
}

上述程序的输出显示foobar指向同一位置(1)。此位置也远离foobar的地址。注意(1)表明它不是转换错误

我尝试将foobar的类型修改为函数指针(例如extern void (*foo)(void)),输出仍然相同。

当然,它可以使用正确的声明extern void foo(void)

我的理解中有什么错误?谢谢。 (我试图纠正我的理解,而不仅仅是让事情有效)

3 个答案:

答案 0 :(得分:2)

您不是要打印符号foobar所引用的地址,而是打印foobar地址的值。

要打印foobar的地址,您需要执行以下操作:

extern void *foo;
extern void *bar;

void main() {
  printf("foo: %p, bar: %p\n", &foo, &bar);
}

答案 1 :(得分:2)

您的代码包含未定义的行为,因为您在不同的翻译单元中将foobar声明为不同类型的标识符。这违反了ISO 9899:2011§6.2.7¶2:

  

引用同一对象或函数的所有声明都应具有兼容类型;   否则,行为未定义。

当您访问静态存储中的变量时,会取消引用它以获取存储在符号中的值(这是全局变量的内容)。符号本身只是静态变量的地址。要获取符号的值,您需要使用&运算符来获取变量的地址,即变量的值。

Ĺ是你混淆的根源,这不是函数所必需的,因为&会自动穿插在需要的位置,参见ISO 9899:2011§6.3.2.1¶4:

  

函数指示符是具有函数类型的表达式。除非它是   sizeof运算符的操作数,_Alignof运算符, 65)或一元&运算符,类型为“函数返回类型<的函数指示符/ em>“转换为具有类型”指向函数返回类型的指针“的表达式。

     

65)因为没有发生这种转换,sizeof_Alignof运算符的操作数仍然是函数指示符,并且违反了6.5.3.4中的约束。

我希望这能解决你的问题。

答案 2 :(得分:0)

首先:宣言应该成为

void foo(void);
void bar(void);

默认情况下,函数已经是extern。所以你在另一个文件中声明时不需要添加extern。和extern void *foo表示您已在另一个文件中声明指针foo并在此文件中使用它。但是你没有在另一个文件中声明指针为void *foo

关于获取相同的地址:2个函数或变量或任何东西可以具有相同的虚拟地址,但它们将映射到不同的内存区域(不同的物理地址)。如果你从%p打印,你得到的是虚拟地址,而不是物理地址。