使用外部指针声明外部函数时出错
error declaring external function with extern pointer
在我的理解中,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) {
}
上述程序的输出显示 foo
和 bar
指向相同的位置 (1)。此外,此位置与 foo
或 bar
的地址相去甚远。注(1)表示不可能不是转换错误
我尝试将foo
和bar
的类型修改为函数指针(例如extern void (*foo)(void)
),结果还是一样。
当然,只要声明正确 extern void foo(void)
。
我的理解有什么错误吗?谢谢。 (我正在尝试纠正我的理解,而不仅仅是让事情正常进行)
您打印的不是符号 foo
和 bar
所指的地址,而是 foo
和 bar
地址处的值。
要打印 foo
和 bar
的地址,您需要执行以下操作:
extern void *foo;
extern void *bar;
void main() {
printf("foo: %p, bar: %p\n", &foo, &bar);
}
第一件事:声明应该变成
void foo(void);
void bar(void);
默认情况下函数已经是外部的。所以你不需要在另一个文件中声明时添加 extern 。 extern void *foo
意味着你已经在另一个文件中声明了指针 foo 并在这个文件中使用它。但是您还没有在另一个文件中将指针声明为 void *foo
.
关于获得相同的地址:2 个函数或变量或任何东西都可以有相同的虚拟地址,但它们将映射到不同的内存区域(不同的物理地址)。当您从 %p 打印时,您得到的是虚拟地址而不是物理地址。
您的代码包含 未定义行为,因为您将 foo
和 bar
声明为不同翻译单元中不同类型的标识符。这违反了 ISO 9899:2011 §6.2.7 ¶2:
All declarations that refer to the same object or function shall have compatible type;
otherwise, the behavior is undefined.
发生的情况是,当您访问静态存储中的变量时,它会被解引用以获取存储在符号处的值(这是全局变量的内容)。符号本身只是静态变量的地址。获取符号的值,需要用&
运算符取变量的地址,也就是符号的值
可能是您混淆的根源,函数不需要它,因为 &
会自动散布在需要的地方,请参见。 ISO 9899:2011 §6.3.2.1 ¶4:
A function designator is an expression that has function type. Except when it is the
operand of the sizeof
operator, the _Alignof
operator,65) or the unary &
operator, a function designator with type “function returning type” is converted to an expression that has type “pointer to function returning type”.
65) Because this conversion does not occur, the operand of the sizeof
or _Alignof
operator remains a function designator and violates the constraints in 6.5.3.4.
我希望这能解决您的问题。
在我的理解中,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) {
}
上述程序的输出显示 foo
和 bar
指向相同的位置 (1)。此外,此位置与 foo
或 bar
的地址相去甚远。注(1)表示不可能不是转换错误
我尝试将foo
和bar
的类型修改为函数指针(例如extern void (*foo)(void)
),结果还是一样。
当然,只要声明正确 extern void foo(void)
。
我的理解有什么错误吗?谢谢。 (我正在尝试纠正我的理解,而不仅仅是让事情正常进行)
您打印的不是符号 foo
和 bar
所指的地址,而是 foo
和 bar
地址处的值。
要打印 foo
和 bar
的地址,您需要执行以下操作:
extern void *foo;
extern void *bar;
void main() {
printf("foo: %p, bar: %p\n", &foo, &bar);
}
第一件事:声明应该变成
void foo(void);
void bar(void);
默认情况下函数已经是外部的。所以你不需要在另一个文件中声明时添加 extern 。 extern void *foo
意味着你已经在另一个文件中声明了指针 foo 并在这个文件中使用它。但是您还没有在另一个文件中将指针声明为 void *foo
.
关于获得相同的地址:2 个函数或变量或任何东西都可以有相同的虚拟地址,但它们将映射到不同的内存区域(不同的物理地址)。当您从 %p 打印时,您得到的是虚拟地址而不是物理地址。
您的代码包含 未定义行为,因为您将 foo
和 bar
声明为不同翻译单元中不同类型的标识符。这违反了 ISO 9899:2011 §6.2.7 ¶2:
All declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
发生的情况是,当您访问静态存储中的变量时,它会被解引用以获取存储在符号处的值(这是全局变量的内容)。符号本身只是静态变量的地址。获取符号的值,需要用&
运算符取变量的地址,也就是符号的值
可能是您混淆的根源,函数不需要它,因为 &
会自动散布在需要的地方,请参见。 ISO 9899:2011 §6.3.2.1 ¶4:
A function designator is an expression that has function type. Except when it is the operand of the
sizeof
operator, the_Alignof
operator,65) or the unary&
operator, a function designator with type “function returning type” is converted to an expression that has type “pointer to function returning type”.65) Because this conversion does not occur, the operand of the
sizeof
or_Alignof
operator remains a function designator and violates the constraints in 6.5.3.4.
我希望这能解决您的问题。