30

我正在使用静态初始化来简化在 C++ 中使用工厂注册某些类的过程。不幸的是,我认为编译器正在优化“未使用”的对象,这些对象旨在在其构造函数中完成有用的工作。有没有办法告诉编译器不要优化全局变量?

class SomeClass {
    public:
        SomeClass() {
            /* do something useful */
        }
};

SomeClass instance;

SomeClass 的构造函数中的断点没有被命中。在我的实际代码中, SomeClass 在头文件中,而实例在源文件中,或多或少是单独的。

编辑:正如 KJAWolf 所猜测的,这段代码实际上被编译成一个静态库,而不是可执行文件。其目的是将静态库也提供的某些类型注册到类型及其创建者的静态列表中,以便工厂在构造时从中读取。由于这些类型是随 lib 提供的,因此不希望将此代码添加到可执行文件中。

我还发现,通过将代码移动到另一个包含其他现有代码的源文件,它可以正常工作。似乎有一个完全由这些全局对象组成的文件是导致问题的原因。就好像那个翻译单元被完全忽略了。

4

9 回答 9

44

不允许编译器优化全局对象。
即使它们从未使用过。

您的代码中正在发生其他事情。
现在,如果您使用全局对象构建了一个静态库,并且该全局对象未从可执行文件中引用,则链接器不会将其拉入可执行文件。

于 2009-08-04T19:47:19.797 回答
5

编译器永远不应该优化掉这样的全局变量——如果这样做,它就会被破坏。

于 2009-08-04T19:44:05.717 回答
2

您可以通过在构建完整的静态库之前部分链接它们来强制一个对象(您的类型列表)与它一起拉一些其他对象。

使用GNU 链接器

ld -Ur -o TypeBundle.o type1.o type2.o type3.o static_list.o
ld -static -o MyStaticLib.a type_bundle.o other_object.o another_object.o ...

因此,每当使用库的代码引用静态列表时,完整的“TypeBundle.o”对象将链接到生成的二进制文件中,包括 type1.o、type2.o 和 type3.o。

在此期间,请查看手册中“-Ur”的含义。

于 2016-08-29T16:46:09.667 回答
1

为了以 Arthur Ulfeldt 为基础,volatile 告诉编译器这个变量可以在编译器不知道的情况下发生变化。我用它来放置一个语句以允许调试器设置断点。它对于可以根据环境更改或需要特殊序列的硬件寄存器也很有用。即串口接收寄存器和某些看门狗寄存器。

于 2009-08-04T19:55:10.280 回答
1

你可以使用

#pragma 优化关闭
全局变量
#pragma 优化

但我不知道这是否仅适用于 Visual Studio(http://msdn.microsoft.com/en-us/library/chh3fb0k(VS.80).aspx)。

您还可以告诉编译器根本不优化,尤其是在调试时...

于 2009-08-04T19:57:24.177 回答
0

你在使用 gcc 和 gdb 吗?过去有一个问题,gdb 无法在构造函数中准确设置断点。

此外,您是否使用了允许编译器在类定义中内联方法的优化级别。

于 2009-08-04T20:02:25.430 回答
0

我在 VS2008 上有相同的设置和问题。我发现如果你声明你的类dllexport不会优化。

class __declspec( dllexport ) Cxxx
{
.
}

但是,在我的情况下,这会产生很多警告,因为我必须将此类中使用的所有类也声明为 dllexport。

所有优化都关闭(在调试模式下),仍然是优化的。还 volatile/pragma 优化关闭。在这个类创建的全局变量上(在同一个 cpp 文件中)等不起作用。

刚刚发现dllexport确实需要至少将这些类的头文件包含在exe的其他一些cpp文件中才能工作!所以唯一的选择是为每个类添加一个调用一些静态成员的文件,并将这个文件添加到所有使用这些类的项目中。

于 2011-02-23T09:46:01.680 回答
0

链接时需要使用 -whole-archive。在这里查看答案:

ld 链接器问题: --whole-archive 选项

于 2011-04-14T16:13:35.310 回答
-1

使用 volatile 关键字怎么样?它将防止编译器进行过多的优化。

于 2009-08-09T01:43:49.097 回答