c++ - 自由函数中静态变量与静态成员函数的区别

标签 c++ static-methods linkage

我有这样的代码:

struct Storage
{
    static int GetData()
    {
            static int global_value;
            return global_value++;
    }
};
int free_func()
{
    static int local_value;
    return local_value++;
}

int storage_test_func()
{
    return Storage::GetData();
}

在 OSX 上编译它:

$ clang++ 1.cpp -shared

并运行 nm:

$ nm | c++filt

我得到了奇怪的结果:

0000000000000f50 T storage_test_func()
0000000000000f30 T free_func()
0000000000000f60 unsigned short Storage::GetData()
0000000000001024 bool free_func()::local_value
0000000000001020 D Storage::GetData()::global_value
                 U dyld_stub_binder

两个符号(local_valueglobal_value)有不同的链接!一个明显的区别是 global_value 是在静态成员函数中定义的,而 local_value 是在自由函数中定义的。

有人能解释一下为什么会这样吗?

更新:

阅读评论后,我似乎应该澄清一些事情。 也许使用 c++filt 是个坏主意。没有它显示:

$ nm

0000000000000f50 T __Z17storage_test_funcv
0000000000000f30 T __Z9free_funcv
0000000000000f60 t __ZN7Storage7GetDataEv
0000000000001024 b __ZZ9free_funcvE11local_value
0000000000001020 D __ZZN7Storage7GetDataEvE5value
                 U dyld_stub_binder

是的。 __ZZ9free_funcvE11local_value 转到 BSS,__ZZN7Storage7GetDataEvE5value 转到数据部分。

man nm 说:

If the symbol is local (non-external), the symbol's type is instead represented by the corresponding lowercase letter.

这就是我所看到的。 __ZZ9free_funcvE11local_value用小写b标记,__ZZN7Storage7GetDataEvE5value用大写D标记。

这是问题的主要部分。为什么会这样?

UPD2 另一种方式:

$ clang++ -c -emit-llvm  1.cpp
$ llvm-dis 1.bc 

显示这些变量在内部是如何表示的:

@_ZZ9free_funcvE11local_value = internal global i32 0, align 4
@_ZZN7Storage7GetDataEvE5value = global i32 0, align 4

UPD3

还有一些关于符号所属的不同部分的担忧。将 __ZZ9free_funcvE11local_value 放入文本部分不会改变其可见性:

struct Storage
{
    static int GetData()
    {
            static int value;
            return value++;
    }
};


int free_func()
{
    static int local_value = 123;
    return local_value++;
}

int storage_test_func()
{
    return Storage::GetData();
}

编译:

$ clang++ 1.cpp -shared

检查:

$ nm

给予:

0000000000000f50 T __Z17storage_test_funcv
0000000000000f30 T __Z9free_funcv
0000000000000f60 t __ZN7Storage7GetDataEv
0000000000001020 d __ZZ9free_funcvE11local_value
0000000000001024 D __ZZN7Storage7GetDataEvE5value

现在两个符号都在数据部分,但仍然其中一个是本地,另一个是全局。 问题是为什么会发生?有人可以了解此类编译器决策的逻辑吗?

最佳答案

静态成员函数中的局部静态变量与自由函数中的局部静态变量没有区别。

Two symbols (local_value and global_value) have different linkage!

在标准命名法中,从标准的角度来看,这两个变量没有联系。

函数之间的相关区别不在于一个是静态成员函数而另一个不是。相关的区别是前者是一个内联函数,而后者不是。

非内联函数只能在一个翻译单元中定义,因此它们的局部静态变量不需要从其他翻译单元访问。

另一方面,内联函数必须在使用它们的每个翻译单元中定义。而且,由于局部静态必须在全局范围内引用同一个对象,因此该对象必须对多个翻译单元可见。

关于c++ - 自由函数中静态变量与静态成员函数的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36952516/

相关文章:

c++ - 如何在C++ XE2中监听用IWebBrowser2运行IE的事件?

c++ - 根据其他参数计算模板参数的惯用方法

java - 静态变量初始化的区别

c++ - 我相信短语 "not previously declared to have external linkage"在 N4140 的§3.5/3 项目符号点 (3.2) 中是多余的

c++ - C++中extern "C"的作用是什么?

c - 使用指向外部变量的指针进行静态初始化

c++ - 指针和数据之间的 union ,可能存在的陷阱?

c++ - 将 char 数组的数组传递给函数

java - 在静态方法中访问全局类的全局方法

c# - 静态函数是否等同于 C# 中的静态 Func 成员?