0
#include <stdio.h>

namespace myname{
    double var = 42;
}

extern "C" double _ZN6myname3varE = 10.0;

int main(){
    printf("%d\n", _ZN6myname3varE);
    return 0;
}

gcc编译结果为:

Jim@ubuntu:~/workspace/vi_edit$ g++ testSymble.cpp -o testSymble
testSymble.cpp:7:19: warning: ‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]
testSymble.cpp: In function ‘int main()’:
testSymble.cpp:10:32: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
/tmp/cczIjRfH.s: Assembler messages:
/tmp/cczIjRfH.s:14: Error: symbol `_ZN6myname3varE' is already defined

为什么_ZN6myname3varE要重新定义?
警告‘_ZN6myname3varE’ initialized and declared ‘extern’ [enabled by default]是什么意思?


如果程序在保留名称的上下文中声明或定义名称,则该行为未定义。

17.4.3.1.2 全局名称
每个包含双下划线 (_ _) 或以下划线后跟大写字母 (2.11) 的名称都保留给实现以供任何使用。

4

2 回答 2

3

为什么_ZN6myname3varE要重新定义?

GCC对C++ 变量myname::var进行了名称修改。_ZN6myname3varE您还定义了一个名为_ZN6myname3varE. 因此,您对同一符号有多个定义。


警告[...]是什么意思?

标准用法是:

foo.h

extern "C" int myvariable;

foo.c/cc

#include "foo.h"

int myvariable = 42;

我不确定 C++ 标准是否允许初始化extern "C"变量(即像你正在做的那样)。但是编译器肯定会警告您,您正在做的事情可能没有意义。

于 2013-07-17T04:42:55.423 回答
0

第一条警告消息意味着如果您extern在变量的声明中包含,则不能同时包含初始化程序。因此,这两行都会生成该警告:

extern "C" int i = 9;
extern     int j = 10;

你可以写:

int i = 9;
int j = 10;

或者:

extern "C" int i;
extern     int j;

或者(正如Adam Rosenfield在评论中指出的那样),您可以在行中包含大括号以允许初始化:

extern "C" { int i = 9; }

应用于您的代码,您不能将初始化程序= 42放在extern "C"行中,或者您需要编写:

extern "C" { double _ZN6myname3varE = 10.0; }

孤立地忽略最后一个问题,这应该“有效”。

第二个警告意味着那namespace myname { double var = 42; }是一个double所以%d转换规范是错误的;它应该是这个主题的%f%e或或变体。%g

printf("%f\n", myname::var);

第三条消息,错误,来自汇编程序。因为第一条消息只是一个警告,你实际上有两个不同的定义,当它们被破坏时,转换为_ZN6myname3varE,具有两个不同的初始值设定项。你只被允许一个定义——一个定义规则。

但是,以下划线后跟大写字母开头的名称是为实现保留的,因此通过尝试_ZN6myname3varE直接使用该名称,您将调用未定义的行为。不要乱搞未定义的行为;躲开它。

于 2013-07-17T05:11:34.643 回答