我有这个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;
}
当我尝试编译时,我收到此错误:error LNK2005: MPI_Cust_ProcessStats_create(void) already defined
。如果我评论#include "ProcessStasts.h"
指令和使用ProcessStats结构的行,则从其中一个文件中正确编译。我甚至试图评论依赖于ProcessStats的所有行,只留下#include "ProcessStasts.h"
语句,我得到这个lnk错误。有什么问题?
答案 0 :(得分:4)
您可以这样写: 首先是ProcessStasts.h
#pragma once
#include <mpi.h>
#include <cstddef>
struct ProcessStats
{
int rank,
itLeft,
crtIt,
processFlag;
float speed;
};
MPI_Datatype MPI_Cust_ProcessStats_create();
然后是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;
}
然后,您可以根据需要多次包含ProcessStasts.h。作为建议,不要在头文件中定义函数。
答案 1 :(得分:2)
#pragma once
指示预处理器不要包含两次头文件。这主要用于防止递归包含和多个间接包含,例如:
#include <a.h> // a.h already includes b.h
#include <b.h>
在#pragma once
开头没有b.h
,其内容将被包含两次,并可能导致重新定义某些符号。
在您的情况下发生的事情是完全不同的事情。默认情况下,C和C ++中的函数具有外部链接。这意味着如果您在文件foo()
中定义了函数bar.c
,然后将bar.c
编译为目标文件bar.o
,则目标文件将按名称导出全局符号foo
(实际上C ++将装饰名称以支持重载),可以从其他目标文件访问(引用)该符号。现在,如果文件baz.c
包含另一个函数foo()
的定义(在C ++的情况下具有相同的签名),则目标文件baz.o
也会导出名称为{的全局符号。 {1}}。当目标文件链接在一起以生成可执行文件时,链接器会尝试将每个符号解析为唯一的内存地址。但现在有一个问题:有两个符号foo
,它们都有不同的地址。链接器(通常)不是通灵的,所以它只是给你一个关于符号重新定义的错误信息并终止。
C和C ++都提供了一种控制函数链接的机制。如果添加foo
关键字,则函数符号不再是全局的,只对共享相同编译单元的代码可见。这些功能具有静态链接。这就是为什么在头文件中定义的函数几乎总是带有static
关键字:
static
现在#pragma once
#include <mpi.h>
#include <cstddef>
struct ProcessStats
{
int rank,
itLeft,
crtIt,
processFlag;
float speed;
};
static MPI_Datatype MPI_Cust_ProcessStats_create()
{
...
}
只会在包含头文件的源文件中显示。
未经请求的建议:MPI_Cust_ProcessStats_create()
前缀是为MPI API调用保留的。将它用于用户函数是一种糟糕的编程习惯,因为有些工具依赖于只有MPI调用以MPI_
开头并且可能会混淆的事实。