Marc van Leeuwen's answer 是正确的:查看当前的working draft,似乎没有什么要求声明extern "C" 的函数隐含noexcept。有趣的是,标准 C++ 禁止 C++ 标准库中的 C 标准库函数抛出异常。这些函数本身通常指定为extern "C"(但这是定义的实现,请参见16.4.3.3-2)。查看子句16.4.6.13 [限制异常处理] 和随附的脚注174 和175。
C 标准库中的函数不应引发异常 [脚注 174],除非此类函数调用程序提供的引发异常的函数。[脚注 175]
脚注 174:
- 也就是说,C 库函数都可以被视为标记为 noexcept。
这允许实现基于运行时不存在异常来进行性能优化。
脚注 175:
函数 qsort() 和 bsearch() ([alg.c.library]) 满足这个条件。
话虽如此,遵循与标准库相同的策略通常是一个很好的设计指南,出于Marc van Leeuwen's answer 中提到的原因,我认为用户定义的extern "C" 函数也可以用noexcept 指定是个好主意, 除非它被传递一个指向 C++ 函数的指针作为回调参数,如 qsort 等。我用clang10、gcc10做了一个小实验,代码如下:
#include <cstring>
#include <cstdlib>
#include <iostream>
extern "C" int cmp(const void* lhs, const void* rhs) noexcept;
extern "C" int non_throwing();
int main()
{
constexpr int src[] = {10, 9, 8, 7, 6, 5};
constexpr auto sz = sizeof *src;
constexpr auto count = sizeof src / sz;
int dest[count];
int key = 7;
std::cout << std::boolalpha
// noexcept is unevaluated so no worries about UB here
<< "non_throwing: " << noexcept(non_throwing()) << '\n'
<< "memcpy: " << noexcept(std::memcpy(dest, src, sizeof dest)) << '\n'
<< "malloc: "<< noexcept(std::malloc(16u)) << '\n'
<< "free: " << noexcept(std::free(dest)) << '\n'
<< "exit: " << noexcept(std::exit(0)) << '\n'
<< "atexit: " << noexcept(std::atexit(nullptr)) << '\n'
<< "qsort: " << noexcept(std::qsort(dest, count, sz, cmp)) << '\n' // should fail
<< "bsearch: " << noexcept(std::bsearch(&key, dest, count, sz, cmp)) << '\n'; // should fail
}
gcc10 和 clang10 的输出是:
non_throwing: false
memcpy: true
malloc: true
free: true
exit: true
atexit: true
qsort: false
bsearch: false
对于 msvc142,如果使用 /EHsc 编译,那么所有输出显然都是 true。而使用 /EHs,所有输出都是错误的,这使得 /EHsc 中的“c”对于严格遵守是必要的。