我无法在标准中找到强制使用extern "C"
声明的函数为noexcept
的任何内容,无论是隐式还是显式。
然而,应该很清楚C调用约定不能支持异常......或者是它?
标准是否提到了这个,我错过了某个地方?如果没有,为什么不呢?它只是作为各种实现细节留下的吗?
答案 0 :(得分:18)
据我所知,不能保证用“C”链接定义的函数不会抛出异常。该标准允许C ++程序调用具有“C”语言链接的外部函数,并定义用C ++编写的具有“C”语言链接的函数。因此,没有什么可以阻止C ++程序调用具有“C”语言链接的函数,该函数实际上是用C ++编写的(在另一个编译单元中可能,尽管这不是必需的)。这样做会很奇怪,但很难排除。此外,我没有看到标准中的哪个位置表示这样做会导致未定义的行为(事实上,由于标准无法定义不是用C ++编写的函数行为,这将是仅用法没有正式未定义的行为)。
因此,我认为假设“C”链接意味着noexcept
是错误的。
答案 1 :(得分:8)
extern "C"
只使用C-linkage,而不是C函数。它阻止编译器执行C++ name mangling。
更直接 - 假设此代码。
// foo.cpp
extern "C" void foo()
{
throw 1;
}
// bar.cpp
extern "C" void foo();
void bar()
{
try
{
foo();
}
catch (int)
{
// yeah!
}
}
答案 2 :(得分:1)
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:
<块引用>脚注 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”必须严格遵守。
答案 3 :(得分:0)
没有任何地方说extern "C"
函数是noexcept
。另一方面,除非您做一些奇怪的事情,否则几乎所有C标准库函数都是noexcept
。通常,这归结为调用未定义的行为,但是还有其他几种情况。这些应该都是它们:
qsort()
的函数指针参数可以抛出;因此qsort()
可以抛出。bsearch()
也是如此。malloc()
,realloc()
和free()
。如果这样做,它们可能会抛出。calloc()
,fopen()
,fclose()
,freopen()
,system()
和strdup()
。 (strdup()
已定义,但不能保证存在。)setjmp()
和catch(...)
不能混用。至少一个平台将longjmp()
实现为与throw jmp_buf
的逻辑等效,从而导致catch(...)
对其进行捕获。catch(...)
捕获。如果您在任何地方执行未定义的行为,那么一旦代码路径不可撤销地致力于达到未定义的行为,整个程序便会变得未定义,因此这可能导致C标准库函数抛出异常。答案 4 :(得分:0)