简体   繁体   English

编译包含结构的h文件时链接错误

[英]Link error while compiling a h file containing a struct

I have this ProcessStasts.h file that is included into two other .h files. 我有这个ProcessStasts.h文件,它包含在另外两个.h文件中。

#pragma once

#include <mpi.h>
#include <cstddef>

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

MPI_Datatype MPI_Cust_ProcessStats_create()
{
    // set data to create new MPI data type
    MPI_Datatype MPI_Cust_ProcessStats;
    MPI_Datatype dataTypes[5] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_FLOAT};
    int blockLengths[5] = {1, 1, 1, 1, 1};
    MPI_Aint offsets[5];

    offsets[0] = (MPI_Aint) offsetof(ProcessStats, rank);
    offsets[1] = (MPI_Aint) offsetof(ProcessStats, itLeft);
    offsets[2] = (MPI_Aint) offsetof(ProcessStats, crtIt);
    offsets[3] = (MPI_Aint) offsetof(ProcessStats, processFlag);
    offsets[4] = (MPI_Aint) offsetof(ProcessStats, speed);

    // create new MPI type based on data from above
    MPI_Type_create_struct(5, blockLengths, offsets, dataTypes, &MPI_Cust_ProcessStats);
    MPI_Type_commit(&MPI_Cust_ProcessStats);

    return MPI_Cust_ProcessStats;
}

When I try compiling I get this error: error LNK2005: MPI_Cust_ProcessStats_create(void) already defined . 当我尝试编译时,我收到此错误: error LNK2005: MPI_Cust_ProcessStats_create(void) already defined If I comment the #include "ProcessStasts.h" directive and the line that uses the ProcessStats struct, from one of the files, it compiles correctly. 如果我对#include "ProcessStasts.h"指令和使用ProcessStats结构的行进行注释,则从其中一个文件中正确编译。 I even tryed to comment all lines dependent in ProcessStats and only leave the #include "ProcessStasts.h" statements and I get this lnk error. 我甚至试图评论依赖于ProcessStats的所有行,只留下#include "ProcessStasts.h"语句,我得到这个lnk错误。 What is wrong? 怎么了?

You can write like this: first is ProcessStasts.h 您可以这样写:首先是ProcessStasts.h

#pragma once

#include <mpi.h>
#include <cstddef>

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

MPI_Datatype MPI_Cust_ProcessStats_create();

then is ProcessStasts.c 然后是ProcessStasts.c

#include "ProcessStats.h"
MPI_Datatype MPI_Cust_ProcessStats_create()
{
    // set data to create new MPI data type
    MPI_Datatype MPI_Cust_ProcessStats;
    MPI_Datatype dataTypes[6] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_FLOAT};
    int blockLengths[5] = {1, 1, 1, 1, 1};
    MPI_Aint offsets[5];

    offsets[0] = (MPI_Aint) offsetof(ProcessStats, rank);
    offsets[1] = (MPI_Aint) offsetof(ProcessStats, itLeft);
    offsets[2] = (MPI_Aint) offsetof(ProcessStats, crtIt);
    offsets[3] = (MPI_Aint) offsetof(ProcessStats, processFlag);
    offsets[4] = (MPI_Aint) offsetof(ProcessStats, speed);

    // create new MPI type based on data from above
    MPI_Type_create_struct(3, blockLengths, offsets, dataTypes, &MPI_Cust_ProcessStats);
    MPI_Type_commit(&MPI_Cust_ProcessStats);

    return MPI_Cust_ProcessStats;
}

Then you can include the ProcessStasts.h as many times as you want. 然后,您可以根据需要多次包含ProcessStasts.h。 As a suggestion, do not define functions in a head file. 作为建议,不要在头文件中定义函数。

#pragma once instructs the preprocessor not to include a header file twice. #pragma once指示预处理器不包括两次头文件。 This is mostly used to prevent recursive inclusions and multiple indirect inclusions, eg: 这主要用于防止递归包含和多个间接包含,例如:

#include <a.h>  // a.h already includes b.h
#include <b.h>

Without #pragma once at the beginning of bh , its content will get included twice and possibly lead to redefinition of some symbols. 如果在bh开头没有#pragma once ,它的内容将被包含两次,并可能导致重新定义某些符号。

What happens in your case is an entirely different matter. 在你的情况下发生的事情是完全不同的事情。 By default functions in C and C++ have external linkage. 默认情况下,C和C ++中的函数具有外部链接。 It means that if you have function foo() defined in file bar.c and then you compile bar.c to the object file bar.o , the object file exports a global symbol by the name of foo (actually C++ will decorate the name in order to support overloading), which symbol can be accessed (referred to) from other object files. 这意味着,如果你有函数foo()在文件中定义bar.c然后编译bar.c到目标文件bar.o ,对象文件导出全局符号由名foo (实际上是C ++将装点名为了支持重载,可以从其他目标文件中访问(引用)哪个符号。 Now if file baz.c contains the definition of another function foo() (which in the case of C++ has the same signature), the object file baz.o also exports a global symbol by the name of foo . 现在,如果文件baz.c包含另一个函数foo()的定义(在C ++的情况下具有相同的签名),则对象文件baz.o也会以foo的名称导出全局符号。 When the object files get linked together in order to produce an executable file, the linker tries to resolve each symbol to a unique memory address. 当目标文件链接在一起以生成可执行文件时,链接器会尝试将每个符号解析为唯一的内存地址。 But now there is a problem: there are two symbols foo and they both have different addresses. 但现在有一个问题:有两个符号foo ,它们都有不同的地址。 The linker is (usually) not a psychic, so it simply gives you an error message about symbol redefinition and terminates. 链接器(通常)不是通灵的,所以它只是给你一个关于符号重新定义的错误消息并终止。

Both C and C++ provide a mechanism to control the linkage of functions. C和C ++都提供了一种控制函数链接的机制。 If you add the static keyword, the function symbol is no longer global and become only visible to the code that shares the same unit of compilation. 如果添加static关键字,则函数符号不再是全局的,只对共享相同编译单元的代码可见。 Such functions have static linkage. 这些功能具有静态链接。 That's why functions that are defined in header files almost always come with the static keyword: 这就是为什么在头文件中定义的函数几乎总是带有static关键字的原因:

#pragma once

#include <mpi.h>
#include <cstddef>

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

static MPI_Datatype MPI_Cust_ProcessStats_create()
{
    ...
}

Now MPI_Cust_ProcessStats_create() is only going to be visible in the source file that includes the header file. 现在, MPI_Cust_ProcessStats_create()仅在包含头文件的源文件中可见。

Unsolicited advice: The MPI_ prefix is reserved for MPI API calls. 未经请求的建议: MPI_前缀保留用于MPI API调用。 Using it for user functions is a bad programming practice since there are tools that rely on the fact that only MPI calls begin with MPI_ and might get confused. 将它用于用户函数是一种糟糕的编程习惯,因为有些工具依赖于只有MPI调用以MPI_并且可能会混淆的事实。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用gralloc_priv.h文件编译时出错 - Error compiling with gralloc_priv.h file 致命错误:strtok_r.h:没有这样的文件或目录(在MinGW中编译tesseract-ocr-3.01时) - fatal error: strtok_r.h: No such file or directory (while compiling tesseract-ocr-3.01 in MinGW) Header 文件未找到错误:<conio.h> 和<process.h>在 macOS Catalina 中的 VScode Cmake 或 Clang++ 中编译时</process.h></conio.h> - Header file not found Error: <conio.h> and <process.h> while compiling in VScode Cmake or Clang++ in macOS Catalina C ++链接错误,找不到global.h结构 - c++ link error, cannot find global.h struct 编译包含QtSerialPort的项目时出现链接器错误(g ++,kubuntu) - Linker error while compiling project containing QtSerialPort (g++, kubuntu) 错误编译:linux / module.h:没有这样的文件或目录 - error compiling: linux/module.h: No such file or directory 使用 map 类型的映射编译头文件时出错<string,struct> - Error compiling header file with a map of type map<string,struct> JNI编译致命错误:jni.h:没有这样的文件或目录 - JNI compiling fatal error: jni.h: No such file or directory 在Visual Studio上编译QT示例时出现链接错误 - Link error while compiling qt example on visual studio 显式链接上的错误-语法错误:缺少&#39;;&#39; 由bazel编译时在“ *”之前 - Errors on explicit link - syntax error : missing ';' before '*' while compiling by bazel
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM