Visual C++中变量与函数冲突链接规范的行为差异原因探究
C++中变量与函数
extern "C"链接冲突的标准层面解释 现象描述
变量场景
当变量先在无extern "C"的环境下声明,后续用extern "C"定义时,Visual C会默认沿用C链接属性,且无编译提示:
extern IntStruct ifcStruct; extern int ifcVar; /* ... */ extern "C" { IntStruct ifcStruct; int ifcVar = 0; }
通过dumpbin /symbols test.obj查看目标文件符号,可见变量使用的是C++风格的名字修饰:
00C 00000000 SECT4 notype External | ?ifcStruct@@3UIntStruct@@A (struct IntStruct ifcStruct) 00D 00000008 SECT4 notype External | ?ifcVar@@3HA (int ifcVar)
函数场景
当函数先在无extern "C"的环境下声明,后续用extern "C"定义时,Visual C++会直接抛出编译错误:
extern void ifcf (); /* ... */ extern "C" void ifcf () {}
错误信息如下:
test.cpp(20): error C2732: linkage specification contradicts earlier specification for 'ifcf' test.cpp(20): note: see declaration of 'ifcf'
补充细节:
extern "C"是否使用大括号包裹不影响上述结果- 函数声明是否携带
extern关键字不影响错误触发 - 变量声明必须加
extern,否则会触发重定义错误;且变量的语言链接属性由首次声明决定
标准层面的解释
C++标准对函数和变量的语言链接属性做出了不同规定:
- 函数的语言链接属性属于其类型的一部分:首次声明函数时(无
extern "C"),默认赋予其C++语言链接属性,这一属性会成为函数类型的组成部分。后续尝试用extern "C"定义该函数,相当于试图修改已确定的函数类型,违反了"同一实体的所有声明必须保持一致"的规则,因此编译器必须报错。 - 变量的语言链接属性独立于其类型:变量的首次声明(无
extern "C")确定了它的C链接属性,后续用extern "C"定义时,编译器会忽略该链接声明,沿用首次声明的属性,因此不会报错,最终生成C风格的修饰符号。
此外标准明确:若实体已被声明为某一语言链接,后续无链接声明的声明可沿用该属性;但先无链接声明、后指定不同链接的情况,对函数是非法的,对变量则允许编译器继承首次声明的链接属性。
总结
Visual C的行为完全符合C标准:
- 函数的链接属性属于类型的一部分,后续声明/定义的链接属性必须与首次声明一致,否则触发编译错误
- 变量的链接属性与类型无关,首次声明的链接属性会被后续定义继承,后续不同的链接声明会被编译器忽略
内容的提问来源于stack exchange,提问作者MattTT
相关产品推荐
相关产品推荐

