草庐IT

c++ - 在内联函数中访问静态全局变量

coder 2024-02-01 原文

我遇到了一个奇怪的问题,我将其缩小到以下测试用例:

inl.h:

inline const char *fn() { return id; }

抄送:

#include <stdio.h>

static const char *id = "This is A";

#include "inl.h"

void A()
{
    printf("In A we get: %s\n", fn());
}

抄送:

#include <stdio.h>

static const char *id = "This is B";

#include "inl.h"

void B()
{
    printf("In B we get: %s\n", fn());
}

extern void A();

int main()
{
    A();
    B();
    return 0;
}

现在,当我用 g++ -O1 a.cc b.cc 编译它时,它似乎工作正常。我得到:

In A we get: This is A
In B we get: This is B

但是如果我用 g++ -O0 a.cc b.cc 编译我得到:

In A we get: This is A
In B we get: This is A

请注意,实际上我在这里尝试使用 C11 语义,但我使用的是 g++,因为 gcc 尚不支持 C11。

现在据我所知,查看 C11 规范和 C++ 规范(C++11 和更早的规范——内联和静态全局变量的语义似乎没有改变),它应该做什么我想要,并且使用-O0时失败是gcc中的错误。

这是正确的,还是规范中有什么我遗漏的地方会导致这种未定义的行为?

编辑

常见的答案似乎声称 fn 需要声明为 static 才能工作。但是根据 C99 规范的 6.7.4.6(C11 规范中的 6.7.4.7——不确定 C++ 规范):

If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit.

因此,由于此处没有明确的 extern,因此它们应该是两个独立的内联函数,彼此之间没有交互。不需要明确的 static

使用显式静态可以解决 C 的问题,但不适用于 C++ 内联成员函数,因为 static 关键字在这种情况下具有完全不同的含义。

最佳答案

您违反了单一定义规则。非静态函数 fn 在您的两个翻译单元中定义不同。一个与 a.cc 中定义的 id 变量绑定(bind),而另一个与 b.cc< 中的="">id 变量绑定(bind)/em>。这些定义在文本上是相同的,但这不足以满足单一定义规则,即使为声明为内联的函数设置了异常(exception),所以您会得到未定义的行为。

您使用的是 C++ 编译器,而不是 C 编译器,因此无论 C11 说什么与您的 C++ 程序表现出的行为无关。在 C++11 中,标准(在 §3.2/5)似乎说明了关于如何允许 fn 引用 id 的规则(重点和省略号是我的):

There can be more than one definition of a … inline function with external linkage (7.1.2) … in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

  • each definition of D shall consist of the same sequence of tokens; and
  • in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3), except that a name can refer to a const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D; and

您对 fn 的定义由相同的标记序列组成,但它们引用 id,它未在 D 中定义,是在两个翻译单元中不是同一个实体,并且在所有定义中都没有相同的值。我在 C++ 标准中没有看到内联函数隐式获取内部链接的规定。 C++11 §7.1.1/7 是这样说的:

A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared const.

如果您在某些优化级别或从某些编译器的某些版本获得了预期的行为,那么您只是获得了特别邪恶的未定义行为版本,尽管有错误但事情似乎有效。

关于c++ - 在内联函数中访问静态全局变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11126496/

有关c++ - 在内联函数中访问静态全局变量的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  6. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  7. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  10. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

随机推荐