c++ - 如果方法是在类内部定义的,则防止编译器删除方法

标签 c++ compilation

免责声明:

我对以下风格是否是“良好做法”的意见不感兴趣。我正在寻找解决问题的答案/方法。

问题:

我正在 cpp 文件中编译一个类。编译过程剥离了我认为“未使用”的方法定义。有什么办法可以防止这种情况发生吗? (参见下面的开发环境示例)

开发环境:

我目前正在使用 g++ --std=c++98。一个完美的解决方案将适用于所有 c++98 标准编译器和更新版本。

示例:

example1.cpp

#include <stdio.h> 

class Example1{
    public: 
    void print(){printf("helloWorld");};

};

编译、汇编和链接该文件不会创建 print() 方法。 (g++ --std=c++98 example1.cpp main.cpp,其中 main.cpp 只是调用打印方法。)

编译这个(没有链接,g++ --std=c++98 -S)将输出:

example1.s

.file   "example1.cpp"
    .text
    .ident  "GCC: (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008"
    .section    .note.GNU-stack,"",@progbits
    .section    .note.gnu.property,"a"
    .align 8
    .long    1f - 0f
    .long    4f - 1f
    .long    5
0:
    .string  "GNU"
1:
    .align 8
    .long    0xc0000002
    .long    3f - 2f
2:
    .long    0x3
3:
    .align 8
4:

这里显然没有生成print()方法。

不好的解决方法

如果我在同一个文件中使用它,我可以让编译器生成方法(见下面的代码)。但是,我正在寻找更好的解决方案。也许编译器选项?

example1.cpp

#include <stdio.h> 

class Example1{
    public: 
    void print(){printf("helloWorld");};

};

// Create a function outside the class, that uses print().
// That way, print will be generated.
void foo(){
    Example1 ex;
    ex.print();
}

备注(编辑):

  • 在类之外定义方法是不行的。
  • Example1main.cpp中使用如下:

main.cpp

class Example1{
    public:        
        void print();
};

int main(){
    Example1 example;

    example.print();

    return 0;
}    

最佳答案

简短的回答是“你不能使用标准 C++”。

较长的答案分为几个部分。

首先,您的变通办法并没有达到您认为的效果。

#include <stdio.h> 

class Example1{
      public: 
      void print(){printf("helloWorld");};
};

// Create a function outside the class, that uses print().
// That way, print will be generated.
void foo(){
    Example1 ex;
    ex.print();
}

这不会阻止编译器“删除”成员函数 Example1::print()。没有什么可以阻止编译器在 foo() 中内联 Example1::print() 的调用,而不是(使用您的措辞)以某种形式生成该函数这(比如说)可以通过链接器解决。

其次,你的“main.cpp”

class Example1{
     public:        
     void print();
 };

int main(){
      Example1 example;

    example.print();

    return 0;
}    

如果它与“example1.cpp”的任一版本在同一项目中使用,则会引入未定义的行为,因为类 Example1 的定义明显不同 - 一个定义了成员函数 print() 在类定义中,而另一个则没有。这打破了单一定义规则,因为您的程序有两个不同的类 Example1 定义。

如果您的第二个“example1.cpp”似乎“有效”(无论您如何评估),那么您就走运了。未定义行为的本质意味着它似乎可以工作。问题是,C++ 标准不提供任何此类保证 - 当行为未定义时,允许编译器做它喜欢做的事 - 你的代码可能看起来“有效”,或者它可能做一些完全不同的事情。

通常处理这种事情的方法是将类 Example1 的定义放在单独的头文件中,例如

// example1.h
#include <stdio.h>
class Example1{
      public: 
      void print(){printf("helloWorld");};
};

然后将该 header 包含在所有需要它的源文件中。例如;

//   example1.cpp

#include "example1.h"

void foo()
{
    Example1 ex;
    ex.print();
}

// main.cpp
#include "example1.h"
int main()
{
    Example1 example;
    example.print();
    return 0;
}

以上两个源文件(example1.cpp 和 main.cpp)可以在同一个程序中安全使用。

由于函数 Example1::print() 是内联定义的,编译器可以自由地内联它。编译器仍然不需要内联,但允许这样做。这意味着,生成的目标文件或可执行文件不一定包含任何可识别(例如通过检查程序集)作为函数 Example1::print() 的内容。在您的示例中,main()foo() 中可能只有调用 printf() 的代码,但没有明显的代码名为 Example1::print() 的函数。

正如另一个答案(您拒绝了,随后被删除)所说,防止内联的唯一方法是在类定义之外定义函数。该函数定义需要恰好位于项目的一个编译单元中。这允许编译器“生成”函数,但在技术上不需要它(智能编译器和链接器仍然允许“删除”该函数)。

关于c++ - 如果方法是在类内部定义的,则防止编译器删除方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59278553/

相关文章:

c# - 显示构建日期

java - Java编译时错误: reached end of file while parsing

compilation - 如何访问 OpenFL 项目 xml 文件中的环境变量

c++ - 更改现有派生类的基类

c++ - RS232通讯经常出错

c++ - 用 C++ 创建一个基本的 UDP 聊天程序

java - 如何编译不同包中的一组java文件,然后使用命令行构建.jar文件?

用于包装任意函数的 C++ 模板类

c++ - 从 VCL 将 delphi 中的属性公开给 C++

assembly - 编译器和汇编器在计算机上的什么地方?