C++11 头文件中定义的函数的重复符号

C++11 头文件中定义的函数的重复符号,c++11,header-files,C++11,Header Files,假设我有一个头文件_ops.hpp,看起来像这样 #pragma once bool systemIsLittleEndian() { uint16_t x = 0x0011; uint8_t *half_x = (uint8_t *) &x; if (*half_x == 0x11) return true; else return false; } 我最初认为它与实现有关,但事实证明,我只需使用 #pragma on

假设我有一个头文件_ops.hpp,看起来像这样

#pragma once

bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
我最初认为它与实现有关,但事实证明,我只需使用

#pragma once

bool systemIsLittleEndian() { return true; }
如果我将其内联,链接器错误就会消失。这不是我想要依赖的东西,因为内联是一个请求而不是保证

是什么导致了这种行为?我不是在处理一个我返回某种单身的场景

还有其他标记为

 bool MY_LIB_EXPORT someFunc();// implemented in `file_ops.cpp`
这些函数是否以某种方式混合了导出函数和普通旧函数?显然,我可以将实现移到文件_ops.cpp中,我很好奇为什么会发生这种情况

如果我将其内联,链接器错误就会消失。这不是我想要依赖的东西,因为内联是一个请求而不是保证

可以内联函数

即使目标代码没有内联,只要函数在不同的翻译单元中没有改变,语言也保证不会导致链接器错误或未定义的行为

如果在数百个.cpp文件中包含.hpp,您可能会注意到一些代码膨胀,但程序仍然正确

是什么导致了这种行为?我不是在处理一个我返回某种单身的场景

include机制可以方便地减少您必须在多个文件中手动创建的代码量,这些文件具有确切的内容。最后,所有包含其他文件的翻译单元都会从它们包含的文件中获取代码行

如果在file1.cpp和file2.cpp中包含文件_ops.hpp,就好像有:

file1.cpp:

bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
file2.cpp:

bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
当编译这两个.cpp文件并将它们链接在一起以创建可执行文件时,链接器会注意到名为systemIsLittleEndian的函数有两个定义。这就是链接器错误的来源

一个解决方案而不使用内联

在不使用内联的情况下,您的问题的一个解决方案是:

在.hpp文件中声明函数。 在相应的.cpp文件中定义它。。 文件_ops.hpp:

bool systemIsLittleEndian(); // Just the declaration.
文件_ops.cpp:

#include "file_ops.hpp"

// The definition.
bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
更新

关于

 bool MY_LIB_EXPORT someFunc();// implemented in `file_ops.cpp`
在网上有很多关于这方面的信息。这是Microsoft/Windows的问题。以下是了解它的几个出发点

如果我将其内联,链接器错误就会消失。这不是我想要依赖的东西,因为内联是一个请求而不是保证

可以内联函数

即使目标代码没有内联,只要函数在不同的翻译单元中没有改变,语言也保证不会导致链接器错误或未定义的行为

如果在数百个.cpp文件中包含.hpp,您可能会注意到一些代码膨胀,但程序仍然正确

是什么导致了这种行为?我不是在处理一个我返回某种单身的场景

include机制可以方便地减少您必须在多个文件中手动创建的代码量,这些文件具有确切的内容。最后,所有包含其他文件的翻译单元都会从它们包含的文件中获取代码行

如果在file1.cpp和file2.cpp中包含文件_ops.hpp,就好像有:

file1.cpp:

bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
file2.cpp:

bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
当编译这两个.cpp文件并将它们链接在一起以创建可执行文件时,链接器会注意到名为systemIsLittleEndian的函数有两个定义。这就是链接器错误的来源

一个解决方案而不使用内联

在不使用内联的情况下,您的问题的一个解决方案是:

在.hpp文件中声明函数。 在相应的.cpp文件中定义它。。 文件_ops.hpp:

bool systemIsLittleEndian(); // Just the declaration.
文件_ops.cpp:

#include "file_ops.hpp"

// The definition.
bool systemIsLittleEndian() {
    uint16_t x = 0x0011;
    uint8_t *half_x = (uint8_t *) &x;
    if (*half_x == 0x11)
        return true;
    else
        return false;
}
更新

关于

 bool MY_LIB_EXPORT someFunc();// implemented in `file_ops.cpp`
在网上有很多关于这方面的信息。这是Microsoft/Windows的问题。以下是了解它的几个出发点


有趣的是,我不敢相信我以前从未遇到过这种情况!有一条评论被删除了,链接有点密集,但据我所知,在头文件中实现的非模板函数内联需要确保只有一个定义,不管编译器是否真的内联它?实际上还有第二种解决方案:将头文件中的函数定义标记为静态。这样,它就成为每个翻译单元的本地文件,即包含头文件的cpp文件,从而消除了重复。@nowaqq,的确如此。太好了,这一切现在都清楚多了!回复:关于符号可见性的编辑,我很欣赏这些链接。我想我已经很好地理解了这个组件,在什么是不需要导出的时候,我错误地假设,如果函数A和B被标记为导出,而C没有,它会以某种方式导致这种情况。它是
值得一提的是,它不是windows独有的,它更多地取决于您正在构建的库的默认符号可见性。通常将“隐藏”视为默认值,其中导出必要的符号。-fvisibility=hidden。与的结合是它的用武之地。例如,setCMAKE_CXX_VISIBILITY_PRESET hidden。这意味着在OSX和Linux上,都需要相应地导出内容,否则会出现链接错误。这在windows上肯定更常见。我认为它也只与共享库相关。我可不是什么专家,你还是少说一点吧!有趣的是,我不敢相信我以前从未遇到过这种情况!有一条评论被删除了,链接有点密集,但据我所知,在头文件中实现的非模板函数内联需要确保只有一个定义,不管编译器是否真的内联它?实际上还有第二种解决方案:将头文件中的函数定义标记为静态。这样,它就成为每个翻译单元的本地文件,即包含头文件的cpp文件,从而消除了重复。@nowaqq,的确如此。太好了,这一切现在都清楚多了!回复:关于符号可见性的编辑,我很欣赏这些链接。我想我已经很好地理解了这个组件,在什么是不需要导出的时候,我错误地假设,如果函数A和B被标记为导出,而C没有,它会以某种方式导致这种情况。值得一提的是,它不是windows独有的,它更多地取决于您正在构建的库的默认符号可见性。通常将“隐藏”视为默认值,其中导出必要的符号。-fvisibility=hidden。与的结合是它的用武之地。例如,setCMAKE_CXX_VISIBILITY_PRESET hidden。这意味着在OSX和Linux上,都需要相应地导出内容,否则会出现链接错误。这在windows上肯定更常见。我认为它也只与共享库相关。我可不是什么专家,你还是少说一点吧!