C++:如何在 header 文件中包含 Paillier.h

C++: How to include Paillier.h in a header file

我有一个 C++ class key_gen 有一些 paillier_ prvkey_t[=29 类型的数据成员=].问题是我不能在我的 header 文件中包含 paillier 库(用 c 编写),比如 key_gen.h。但是我可以使用

将它包含在我的key_gen.cpp
extern "C"{
#include<paillier.h>
}

我正在使用 cygwin 运行 我的代码,我使用命令行如下:

g++ Key_Gen.cpp -L/cygdrive/c/cygwin/home/Win7/libpaillier -l:libpaillier.a -      
-lgmpxx -lgmp

只要我将 paillier header 包含到我的 header 文件中,当我 运行 代码时,cygwin 就会发出警报。

错误包含多行,例如:

In file included from Key_Gen.h:13:0,
from Key_Gen.cpp:2:
/usr/local/include/paillier.h:63:3: note: previous declaration as ‘typedef   
struct paillier_pubkey_t paillier_pubky_t’} paillier_pubkey_t;
                                            ^

谁能告诉我如何解决这个问题?

当您告诉 C 或 C++ 编译器处理文件时,foo.cpp,编译的第一阶段是预处理,它扩展宏,替换定义和扩展预处理器指令,例如 #include.

早期,预处理器是一个单独的程序,它会即时生成输出:C 编译器本身并不知道 #include,它看到的只是一个代码流.

如今,预处理器通常是编译器(gcc、MSVC 等)不可或缺的一部分,但您在命令行上指定的每个源文件的单流效果保持不变,您仍然可以访问编译器将预处理的输出生成为单个中间文件,以便您可以查看正在进行的翻译(gcc/g++ 的 -E 选项)。所以如果你写:

// Foo.h
int foo;

// Bar.cpp
#include "Foo.h"
int bar;
#include "Foo.h"

编译器看到的是单个连续流:

/* "Bar.cpp" from command line */
// Bar.cpp
/* "Foo.h" from Bar.cpp:2 */
int foo;
/* end "Foo.h" */
int bar;
/* "Foo.h" from Bar.cpp:4 */
int foo;
/* end "Foo.h" */
/* end "Bar.cpp" */
  • 编译阶段不知道#include,
  • 预处理器默认不对 #include 进行重复数据删除,因此多个包含会产生重复。

如果您想将 paillier.h 添加到您自己的 .h 文件中,您需要防止这种重复。有两种常见的方法可以做到这一点。

  1. pragma 守卫

在 .h 文件的开头使用预处理器指令 #pragma,GNU C 和 C++ 编译器都能理解:

#pragma once

Pro:预处理器检测到 #include 语句中的重复项,因此不必重新读取文件。 缺点:大多数编译器使用包含文件的路径来执行此操作,因此

#include "../include/foo.h"
#include "foo.h"

可能都引用同一个文件,但在某些编译器上仍会产生重复。

  1. #ifndef 守卫

在 .h 文件的开头检查唯一预处理器符号的定义,如果未定义,则定义它

#ifndef PAILLIER_H
#define PAILLIER_H

并且在文件的最后

#endif // PAILLIER_H  (comment is optional)

Pro:无论路径如何,都进行重复数据删除。 缺点:如果你的 guard 名称不够独特,可能会导致问题(我在一个项目中工作,有人在多个头文件中使用了 'HEADER') 缺点:预处理器仍然必须读取整个头文件才能找到#endif.

总结

您可能还想添加以下内容,使您的文件在从 C 和 C++ 包含时都能正常工作

#ifdef __cplusplus
extern "C" {
#endif

// all your symbols etc here

#ifdef __cplusplus
}; // extern "C"
#endif

这将使您的头文件看起来像这样:

#ifndef PAILLIER_H
#define PAILLIER_H

#ifdef __cplusplus
extern "C" {
#endif

// original code here
...
// end original code

#ifdef __cplusplus
}; // extern "C"
#endif

#endif // PAILLIER_H

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

// original code here
...
// end original code

#ifdef __cplusplus
}; // extern "C"
#endif

--- 编辑 ---

没有理由不能同时使用两者

#pragma once
#ifndef MYPROJECT_SOMETHING_H
...
#endif

这样,如果#pragma 由于路径原因使您失败,您仍然会被覆盖。