C中的静态断言

Mat*_*ner 79 c gcc assert static-assert compile-time

在C(而不是C++)中实现编译时静态断言的最佳方法是什么,特别强调GCC?

Nor*_*ame 84

这适用于功能和非功能范围(但不在结构,联合内部).

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]

STATIC_ASSERT(1,this_should_be_true); 

int main()
{
 STATIC_ASSERT(1,this_should_be_true); 
}
Run Code Online (Sandbox Code Playgroud)
  1. 如果编译时断言无法匹配,则GCC会生成几乎可理解的消息 sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative

  2. 可以或应该更改宏以生成typedef的唯一名称(即名称__LINE__末尾的连接static_assert_...)

  3. 这也可以使用,而不是三元,这#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]甚至可以在生锈的olde cc65(用于6502 cpu)编译器上工作.

更新: 为了完整起见,这里是版本__LINE__

#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X)    COMPILE_TIME_ASSERT2(X,__LINE__)

COMPILE_TIME_ASSERT(sizeof(long)==8); 
int main()
{
    COMPILE_TIME_ASSERT(sizeof(int)==4); 
}
Run Code Online (Sandbox Code Playgroud)

UPDATE2:GCC特定代码

GCC 4.3(我猜)引入了"错误"和"警告"功能属性.如果通过死代码消除(或其他措施)无法消除对具有该属性的函数的调用,则会生成错误或警告.这可以用于使用用户定义的故障描述来编译时间断言.它仍然是确定如何在名称空间范围内使用它们而不需要使用虚函数:

#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })

// never to be called.    
static void my_constraints()
{
CTC(sizeof(long)==8); 
CTC(sizeof(int)==4); 
}

int main()
{
}
Run Code Online (Sandbox Code Playgroud)

这就是它的样子:

$ gcc-mp-4.5 -m32 sas.c 
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true
Run Code Online (Sandbox Code Playgroud)

  • 在 Visual Studio 中它只是说“负下标”,没有提到变量名...... (2认同)

ems*_*msr 80

C11标准添加了_Static_assert关键字.

这是从gcc-4.6开始实现的:

_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
Run Code Online (Sandbox Code Playgroud)

第一个槽需要是一个整数常量表达式.第二个槽是一个常量字符串文字,可以是long(_Static_assert(0, L"assertion of doom!")).

我应该注意到,这也是在最新版本的clang中实现的.

  • *[...似乎是由gcc实现的,通过clang ...]*你可以更加*断言*那个;-)`_Static_assert`是C11标准的一部分,任何支持C11的编译器都会拥有它. (4认同)
  • 这可以在文件范围内使用吗(在任何函数之外)?因为我在行 `static_assert( sizeof(int) == sizeof(long int), "Error!);` 的 'sizeof'` 之前得到 `error: expected declaration specifiers or '...' (我使用的是 C 而不是 C++顺便一提) (2认同)
  • @ user10607我还必须在命令行中指定-std = gnu11.我真的很惊讶4.8和4.8之间存在差异.我有一个只有一行的来源.我还使用了C标准`_Static_assert`而不是C++ ish`static_assert`.你需要`#include <assert.h>来获取static_assert宏. (2认同)

Gab*_*les 17

作为复活节礼物,这个答案在 2022 年 4 月 17 日得到了极大的改善。我相信这是这里最彻底和完整的答案,因为我已经制作了 3 个不同复杂度的独立解决方案来涵盖不同版本的 C 和 C++,而且由于我提供的最后一个版本涵盖了C 和 C++ 的所有版本,最初是看似不可能的壮举。

\n

您可以在我的文件static_assert_for_all_versions_of_c_and_cpp.c中查看和测试以下所有版本的 C 和 C++ 代码。

\n

请注意C++ style comments are not allowed in ISO C90,因此我的代码示例必须仅使用 C 样式注释 ( /* */),而不是 C++ 样式注释,以便我的代码也//能够编译。-std=c90

\n

快速摘要(TLDR)以获得STATIC_ASSERT(test_for_true)

\n

如果您想要一个快速且超级简单的宏可以在任何版本的 C(使用 gcc 编译时)或C++11 或更高版本的任何版本的 C++ 中工作,请参阅我在底部的两个简单的宏块下一节:“C 和 C++ 中可用的静态断言声明摘要”。以下是为方便起见而复制和粘贴的宏,后面是适用于任何版本的 C 或 C++ 的更复杂但通用的STATIC_ASSERT(test_for_true)宏。这是我的3个主要解决方案:

\n
    \n
  1. [迄今为止最简单的选项!]仅STATIC_ASSERT(test_for_true)适用于C11 或更高版本以及仅 C++11 或更高版本

    \n
    #include <assert.h>\n#define STATIC_ASSERT(test_for_true) \\\n    static_assert((test_for_true), "(" #test_for_true ") failed")\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 或者 [我的偏好],STATIC_ASSERT(test_for_true)对于任何版本的 C(使用 gcc 编译器时作为 gcc 扩展),包括 C89/C90、C99、C11、C17 等,以及C++11 或更高版本(无法处理旧版本) C++):

    \n
    #ifdef __cplusplus\n    #ifndef _Static_assert\n        #define _Static_assert static_assert\n    #endif\n#endif\n\n// Option 1: static assert for which you provide the failure message\n#define STATIC_ASSERT(test_for_true, failure_message) \\\n    _Static_assert((test_for_true), failure_message)\n\n// Option 2: static assert for which the failure message is auto-generated\n#define STATIC_ASSERT2(test_for_true) \\\n    _Static_assert((test_for_true), "(" #test_for_true ") failed")\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. STATIC_ASSERT(test_for_true)对于任何版本的 C 和任何版本的 C++:

    \n

    如果您希望单个STATIC_ASSERT宏适用于所有版本的 C 和 C++,我将在下面以“我的最终版本”开头的部分中介绍它。您可以在底部的“测试摘要”部分中查看我用来测试它的构建命令和语言设置。让静态断言在C++11 之前的版本中工作,例如 C++98、C++03 等,是困难的部分!下面的宏_Static_assert_hack是处理那些早期版本的 C++ 的。以下是处理所有版本的 C 和 C++ 的完整代码块,为了方便起见,删除了大部分注释:

    \n
    // See: https://stackoverflow.com/a/54993033/4561887\n\n#define CONCAT_(prefix, suffix) prefix##suffix\n#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)\n#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)\n\n/* Static assert hack required for **pre-C++11**, such as C++98, C++03, etc.\n * - It works only with C++, NOT with C! \n */\n#define _Static_assert_hack(expression, message) \\\n    struct MAKE_UNIQUE_VARIABLE_NAME(static_assertion_failed) \\\n    { \\\n        _Pragma("GCC diagnostic push") \\\n        _Pragma("GCC diagnostic ignored \\"-Wunused-local-typedefs\\"") \\\n        typedef char static_assertion_failed[(expression) ? 1 : -1]; \\\n        _Pragma("GCC diagnostic pop") \\\n    }\n\n/* For C++ only:\n * See: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html \n */\n#ifdef __cplusplus\n    #if __cplusplus < 201103L\n        /* for pre-C++11 */\n        #ifndef _Static_assert\n            #define _Static_assert _Static_assert_hack\n        #endif\n    #else\n        /* for C++11 or later */\n        #ifndef _Static_assert\n            #define _Static_assert static_assert\n        #endif\n    #endif\n#endif\n\n/* For C **and** C++: */\n#define STATIC_ASSERT(test_for_true) \\\n    _Static_assert((test_for_true), "(" #test_for_true ") failed")\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
\n

C 和 C++ 中可用的静态断言声明摘要:

\n

知道对于:

\n
    \n
  1. C 语言:在C11 或更高版本_Static_assert(expression, message)中可用。\n
      \n
    1. 根据上面的 cppreference.com 社区 wiki 链接,static_assert还可以作为_Static_assert标头中的便捷宏使用<assert.h>,以便与 C++11 中的命名相匹配。因此,要在C11 或更高版本中将类似 C++ 的static_assert宏作为宏,您还应该.#include <assert.h>
    2. \n
    3. _Static_assert(expression)(即:没有该message部件)自C23 或更高版本起也可用。
    4. \n
    \n
  2. \n
  3. C++ 语言:在C++11 或更高版本static_assert(expression, message)中可用。\n
      \n
    1. static_assert(expression)(即:没有该message部分)也可用于C++17 或更高版本
    2. \n
    \n
  4. \n
  5. gcc 编译器:\n
      \n
    1. gcc 编译器版本 4.6 及更高版本开始所有C 版本_Static_assert都支持作为gcc 扩展,包括 c90、c99、c11、c17 等。\n
        \n
      1. 而且,根据 C11 标准,如上所述,如果您也static_assert可以将其用作 C11 或更高版本的宏。_Static_assert#include <assert.h>
      2. \n
      \n
    2. \n
    3. g++ 编译器版本 4.3 及更高版本开始static_assert支持作为C++11 或更高版本的关键字。您不需要#include <assert.h>像在 C 中那样在 C++ 中获得这种格式。
    4. \n
    5. GCC 来源: https: //www.gnu.org/software/gnulib/manual/html_node/assert_002eh.html(添加了重点):
    6. \n
    \n
    \n

    甚至更老的平台也不支持static_assert_Static_assert根本不支持。例如,4.6之前的GCC版本不支持_Static_assert4.3之前的G++版本不支持static_assert,这是由C11和C++11标准化的。

    \n

    C_Static_assert和 C++static_assert是可以在不包含<assert.h>. Gnulib 替代品是需要包含<assert.h>.

    \n
    \n
      \n
    1. 另请参阅: https: //gcc.gnu.org/wiki/C11Status --我从主要答案中获得了此链接。
    2. \n
    \n
  6. \n
\n

我喜欢编写一个STATIC_ASSERT包装宏来将参数减少到 1 并自动生成message参数,这样我就可以STATIC_ASSERT(expression)代替STATIC_ASSERT(expression, message). 以下是如何轻松做到这一点的方法:

\n
    \n
  1. 适用于C11 或更高版本以及仅 C++11 或更高版本:\n
    #include <assert.h>\n#define STATIC_ASSERT(test_for_true) \\\n    static_assert((test_for_true), "(" #test_for_true ") failed")\n
    Run Code Online (Sandbox Code Playgroud)\n
  2. \n
  3. 或者 [我的偏好],对于任何版本的 C(使用 gcc 编译器时作为 gcc 扩展),包括 C90、C99、C11、C17 等,以及C++11 或更高版本(无法处理旧版本的 C++ ):\n
    #ifdef __cplusplus\n    #ifndef _Static_assert\n        #define _Static_assert static_assert\n    #endif\n#endif\n#define STATIC_ASSERT(test_for_true) \\\n    _Static_assert((test_for_true), "(" #test_for_true ") failed")\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. 对于早于 C++11的 C++ 版本,您必须使用 hack 来获取功能静态​​断言。使用下面介绍的相当复杂的C++11 之前的静态断言 hack,或者(更好!),只需升级到 C++11 或更高版本。
  6. \n
\n

在我的static_assert_for_all_versions_of_c_and_cpp.c中测试上述代码片段。

\n

针对非 gcc pre-C11pre-C++11 的静态断言hack

\n

1/2。仅适用于 C(例如:对于非 gcc pre-C11有用)

\n

对于C11 之前的gcc ,gcc 已经定义了_Static_assert(expression, message),这非常好。因此,只需使用它即可完成,如上所述!但是,如果您不使用 gcc 编译器怎么办?你能做什么?

\n

嗯,我注意到一些非常有趣的事情。如果我_Static_assert(1 > 2, "this should fail");在 C90 中与 gcc 一起使用,请使用以下构建命令:

\n
gcc -Wall -Wextra -Werror -O3 -std=c90 \\\n    static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a\n
Run Code Online (Sandbox Code Playgroud)\n

我收到此失败的编译时错误_Static_assert。这是一个超级奇怪的错误!但这不是一个意外的构建错误,这是静态断言失败错误,因为他们还使用此版本的 C 的 hack来获取编译时静态断言!

\n
In file included from /usr/include/features.h:461,\n                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,\n                 from /usr/include/stdint.h:26,\n                 from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9,\n                 from static_assert_for_all_versions_of_c_and_cpp.c:73:\nstatic_assert_for_all_versions_of_c_and_cpp.c: In function \xe2\x80\x98main\xe2\x80\x99:\nstatic_assert_for_all_versions_of_c_and_cpp.c:224:5: error: negative width in bit-field \xe2\x80\x98__error_if_negative\xe2\x80\x99\n  224 |     _Static_assert(1 > 2, "this should fail");\n      |     ^~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

如果我转到 GitHub 上的 gcc 源代码镜像(https://github.com/gcc-mirror/gcc),克隆存储库,然后__error_if_negative使用 grep 或 ripgrep 进行搜索,我只在一个位置找到结果,这里: https: //github.com/gcc-mirror/gcc/blob/master/libgcc/soft-fp/soft-fp.h#L69-L71

\n
In file included from /usr/include/features.h:461,\n                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,\n                 from /usr/include/stdint.h:26,\n                 from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9,\n                 from static_assert_for_all_versions_of_c_and_cpp.c:73:\nstatic_assert_for_all_versions_of_c_and_cpp.c: In function \xe2\x80\x98main\xe2\x80\x99:\nstatic_assert_for_all_versions_of_c_and_cpp.c:224:5: error: negative width in bit-field \xe2\x80\x98__error_if_negative\xe2\x80\x99\n  224 |     _Static_assert(1 > 2, "this should fail");\n      |     ^~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

这是一个静态断言 hack,您可以在 C11 之前的 C 的非 gcc 版本中借用和使用!

\n

只需替换_FP_STATIC_ASSERT_Static_assert,如下所示:

\n
# define _FP_STATIC_ASSERT(expr, msg)                   \\\n  extern int (*__Static_assert_function (void))             \\\n    [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]\n
Run Code Online (Sandbox Code Playgroud)\n

使用_Static_assert上面的 hack 的注意事项:

\n
    \n
  1. 它只适用于 C,不适用于 C++!
  2. \n
  3. 它在 ISO C 中的结构或联合内部不起作用 - 即:当您使用-std=c90等时-std=c99。\n
      \n
    1. 我相信,如果您使用 gnu C 语言,例如或,它确实有效-std=gnu90-std=gnu99
    2. \n
    3. 如果您尝试在联合或结构中使用它,如下所示:\n
      # define _Static_assert(expr, msg)                   \\\n  extern int (*__Static_assert_function (void))             \\\n    [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]\n
      Run Code Online (Sandbox Code Playgroud)\n...然后你会看到这个关于 的超级神秘错误expected specifier-qualifier-list before \xe2\x80\x98extern\xe2\x80\x99。这并不是因为静态断言表达式失败(为假),而是因为静态断言黑客在此用例中被破坏。请注意,extern上面的 hack 中使用了 ,因此,它显示在错误中:\n
      eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c90 static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a\nIn file included from /usr/include/features.h:461,\n                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,\n                 from /usr/include/stdint.h:26,\n                 from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9,\n                 from static_assert_for_all_versions_of_c_and_cpp.c:73:\nstatic_assert_for_all_versions_of_c_and_cpp.c:193:5: error: expected specifier-qualifier-list before \xe2\x80\x98extern\xe2\x80\x99\n  193 |     _Static_assert(2 > 1, "this should pass");\n      |     ^~~~~~~~~~~~~~\n
      Run Code Online (Sandbox Code Playgroud)\n
    4. \n
    \n
  4. \n
\n

2/2。仅适用于 C++(例如:对于C++11 之前的版本有用)

\n

我发现在 C++11 之前的 C++ 中获得一个很好的静态断言 hack 非常棘手,但我成功了!它确实是一件艺术品,但它看起来确实有效,而且运行良好且坚固耐用。它也可以像 C++11 一样在结构体和联合体中工作static_assert!这里是。您可以在我的static_assert_for_all_versions_of_c_and_cpp.c中测试它:

\n
typedef union data_u\n{\n    data_t data;\n    uint8_t bytes[sizeof(data_t)];\n\n    _Static_assert(2 > 1, "this should pass");\n    _Static_assert(5 > 4, "this should pass");\n} data_union_t;\n
Run Code Online (Sandbox Code Playgroud)\n

我的最终版本:当使用 gcc 编译时,STATIC_ASSERT()适用于所有版本的 C 和所有版本的 C++

\n

只需进行一些调整来更改使用的样式和时间,下面的代码也可以在非 gcc 编译器上与任何版本的 C 和 C++一起使用。

\n

正如它所写的,我希望它在使用 gcc/g++ 编译器LLVM clang 编译器编译时适用于所有版本的 C 和 gnu C 以及所有版本的 C++ 和 gnu++。

\n

这是最终版本:一个静态断言可以处理任何版本的 C 或 C++!:

\n
eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=c90 static_assert_for_all_versions_of_c_and_cpp.c -o bin/a -lm && bin/a\nIn file included from /usr/include/features.h:461,\n                 from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,\n                 from /usr/include/stdint.h:26,\n                 from /usr/lib/gcc/x86_64-linux-gnu/9/include/stdint.h:9,\n                 from static_assert_for_all_versions_of_c_and_cpp.c:73:\nstatic_assert_for_all_versions_of_c_and_cpp.c:193:5: error: expected specifier-qualifier-list before \xe2\x80\x98extern\xe2\x80\x99\n  193 |     _Static_assert(2 > 1, "this should pass");\n      |     ^~~~~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

我用来帮助我构建这个的参考资料位于上面源代码的注释中。以下是从那里复制的可点击链接:

\n
    \n
  1. [我的答案]如何使用宏自动生成带有行号的唯一变量名称\n
      \n
    1. 我主要是从这里的@Jarod42 那里学到了这一点,也从这里的@Adam.Rosenfield 那里学到了这一点
    2. \n
    \n
  2. \n
  3. 信息。on _Pragma():如何禁用几行代码的 GCC 警告
  4. \n
  5. typedef char这个数组 hack 作为结构的灵感\n定义:\n
      \n
    1. 由@Nordic.Mainframe 回答
    2. \n
    3. gcc 源代码静态断言 hack
    4. \n
    \n
  6. \n
  7. gcc 预定义宏:\n
      \n
    1. https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
    2. \n
    3. https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
    4. \n
    \n
  8. \n
\n

C++03 示例静态断言错误输出:

\n

STATIC_ASSERT在 C++11 之前的用例中使用上述内容,下面是一些带有静态断言的示例代码,该断言预计会失败,因为它是 false:

\n
#define CONCAT_(prefix, suffix) prefix##suffix\n#define CONCAT(prefix, suffix) CONCAT_(prefix, suffix)\n#define MAKE_UNIQUE_VARIABLE_NAME(prefix) CONCAT(prefix##_, __LINE__)\n\n/* Static assert hack required for **pre-C++11**, such as C++98, C++03, etc. */\n/* - It works only with C++, NOT with C! */\n#define _Static_assert_hack(expression, message) \\\n    struct MAKE_UNIQUE_VARIABLE_NAME(static_assertion_failed) \\\n    { \\\n        _Pragma("GCC diagnostic push") \\\n        _Pragma("GCC diagnostic ignored \\"-Wunused-local-typedefs\\"") \\\n        typedef char static_assertion_failed[(expression) ? 1 : -1]; \\\n        _Pragma("GCC diagnostic pop") \\\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

这是构建命令和失败输出的样子。对于 C++ 中的一个失败的静态断言来说,这是一大堆错误,但这对于像这样的 hack 来说是可以预料的,而_Static_assert上面介绍的 gcc C90 hack for 也好不到哪儿去:

\n
eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=c++03 static_assert_for_all_versions_of_c_and_cpp.c -o bin/a && bin/a\nstatic_assert_for_all_versions_of_c_and_cpp.c:129:67: error: narrowing conversion of \xe2\x80\x98-1\xe2\x80\x99 from \xe2\x80\x98int\xe2\x80\x99 to \xe2\x80\x98long unsigned int\xe2\x80\x99 is ill-formed in C++11 [-Werror=narrowing]\n  129 |         typedef char static_assertion_failed[(expression) ? 1 : -1]; \\\n      |                                                                   ^\nstatic_assert_for_all_versions_of_c_and_cpp.c:139:36: note: in expansion of macro \xe2\x80\x98_Static_assert_hack\xe2\x80\x99\n  139 |             #define _Static_assert _Static_assert_hack\n      |                                    ^~~~~~~~~~~~~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:151:5: note: in expansion of macro \xe2\x80\x98_Static_assert\xe2\x80\x99\n  151 |     _Static_assert((test_for_true), "(" #test_for_true ") failed")\n      |     ^~~~~~~~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:187:5: note: in expansion of macro \xe2\x80\x98STATIC_ASSERT\xe2\x80\x99\n  187 |     STATIC_ASSERT(2 > 2);\n      |     ^~~~~~~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:129:59: error: size \xe2\x80\x98-1\xe2\x80\x99 of array \xe2\x80\x98static_assertion_failed\xe2\x80\x99 is negative\n  129 |         typedef char static_assertion_failed[(expression) ? 1 : -1]; \\\n      |                                              ~~~~~~~~~~~~~^~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:139:36: note: in expansion of macro \xe2\x80\x98_Static_assert_hack\xe2\x80\x99\n  139 |             #define _Static_assert _Static_assert_hack\n      |                                    ^~~~~~~~~~~~~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:151:5: note: in expansion of macro \xe2\x80\x98_Static_assert\xe2\x80\x99\n  151 |     _Static_assert((test_for_true), "(" #test_for_true ") failed")\n      |     ^~~~~~~~~~~~~~\nstatic_assert_for_all_versions_of_c_and_cpp.c:187:5: note: in expansion of macro \xe2\x80\x98STATIC_ASSERT\xe2\x80\x99\n  187 |     STATIC_ASSERT(2 > 2);\n      |     ^~~~~~~~~~~~~\ncc1plus: all warnings being treated as errors\n\n
Run Code Online (Sandbox Code Playgroud)\n

测试总结

\n

请参阅static_assert_for_all_versions_of_c_and_cpp.c

\n

STATIC_ASSERT(test_for_true)我在上面展示的最终宏(可处理所有版本的 C 和 C++)已在 Linux Ubuntu 20.04 上使用 gcc 编译器版本 ( gcc --version) 9.4.0( gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0) 进行了测试。

\n

以下是它经过测试和工作的各种构建命令和语言。同样,在所有这些版本中,唯一不允许在结构和联合内部使用宏的版本是和!所有其他选项都支持在您想要的任何地方使用,包括函数外部、函数内部以及结构和联合内部。STATIC_ASSERT()-std=c90-std=c99STATIC_ASSERT

\n
# -------------------\n# 1. In C:\n# --------


bob*_*ogo 11

CL

我知道这个问题明确提到了gcc,但为了完整性,这里是微软编译器的一个调整.

使用负大小的数组typedef并不能说服cl吐出一个不错的错误.它只是说error C2118: negative subscript.在这方面,零宽度位域的表现更好.由于这涉及对struct进行类型化,我们确实需要使用唯一的类型名称.__LINE__没有削减芥末 - 可能COMPILE_TIME_ASSERT()在标题和源文件中有一个相同的行,你的编译将会中断.__COUNTER__来救援(自4.3以来它一直在gcc).

#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
    typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
        CTASTR(static_assertion_failed_,__COUNTER__)
Run Code Online (Sandbox Code Playgroud)

现在

STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
Run Code Online (Sandbox Code Playgroud)

cl得到:

错误C2149:'static_assertion_failed_use_another_compiler_luke':命名位字段的宽度不能为零

Gcc还提供了一个可理解的消息:

错误:位字段的零宽度'static_assertion_failed_use_another_compiler_luke'


归档时间:

查看次数:

63552 次

最近记录:

6 年,4 月 前