如何在C++中可移植地使用含C99 restrict关键字的头文件?
符合标准的C/C++兼容含C99关键字头文件的方案
我们通常用extern "C" { ... }在C中引入C头文件,但当头文件包含restrict这类C99关键字时,C编译会报错——因为restrict并非C++标准关键字。以下是具体示例及标准可移植解决方案:
问题示例代码
test.h
#ifndef TEST_H #define TEST_H extern void test(int * restrict x, const int * restrict y); #endif
test.c
#include "test.h" int main(void) { int n = 1; int m = 2; test(&n, &m); return 0; }
test.cpp
extern "C" { #include "test.h" } int main(void) { int n = 1; int m = 2; test(&n, &m); return 0; }
C代码用gcc -Wall -Wextra -Wpedantic test.c -c或clang -Weverything test.c -c可正常编译,但C++代码用g++ test.cpp -c或clang++ test.cpp -c会因restrict关键字报错。
符合标准的可移植解决方案
核心思路是利用C/C++标准规定的预处理器差异,在头文件中针对不同编译环境处理C99关键字:
方案1:纯标准兼容方案(推荐)
利用C标准强制要求的__cplusplus预定义宏,在C环境下将restrict定义为空,C环境保留原关键字语义:
修改后的test.h:
#ifndef TEST_H #define TEST_H #ifdef __cplusplus # define restrict /* 空定义,消除C++编译报错 */ #endif extern void test(int * restrict x, const int * restrict y); #ifdef __cplusplus # undef restrict /* 避免影响后续代码 */ #endif #endif
该方案的合规性依据:
- C++标准明确要求编译器必须定义
__cplusplus宏,而标准C环境(C99及以上)不会定义此宏。 - 在C中,将未定义标识符定义为空是合法的预处理器操作,处理后的函数声明符合C语法,同时
extern "C"保证了函数的C语言链接属性。 - 在C环境中,
restrict保持原关键字的语义,完全符合C99标准。
方案2:准可移植的语义贴近方案
如果希望在C中保留类似restrict的编译器优化提示(C无标准等效关键字,但主流编译器提供扩展),可将restrict映射为编译器支持的__restrict扩展:
#ifndef TEST_H #define TEST_H #ifdef __cplusplus # define restrict __restrict #endif extern void test(int * restrict x, const int * restrict y); #ifdef __cplusplus # undef restrict #endif #endif
注意:__restrict是编译器扩展(GCC、Clang、MSVC均支持),并非C++标准内容,属于准可移植方案。若严格要求100%符合标准,优先选择方案1。
内容的提问来源于stack exchange,提问作者Ryan Maguire
相关产品推荐
相关产品推荐

