【问题标题】:How do I test if _Static_assert is defined?如何测试 _Static_assert 是否已定义?
【发布时间】:2021-06-30 07:22:22
【问题描述】:

_Static_assert 内置于一些 C 编译器,例如 gcc 和 clang,但它可能不会包含在所有 C 编译器中。我想使用_Static_assert 功能,同时让我的代码尽可能跨平台。我认为最好的方法是测试

#ifdef _Static_assert
    _Static_assert(0, "Test");
#endif

但这似乎并不奏效。它可以编译,但没有检测到 _Static_assert 已定义。然后我想我可以测试编译器是否是 GCC,但我读到定义 __GNUC__ 并不一定证明使用的编译器是 GCC。这也不会检测到我可能不知道的定义了_Static_assert 的其他编译器。所以我的问题是,检测编译器是否在预处理器中支持_Static_assert 的最佳方法是什么?

编辑: 这是我想出的适合我目的的解决方案。感谢下面的@KamilCuk 提供了帮助我的链接。

// Check that we can use built-in _Static_assert
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
    #define WE_HAVE_STATIC_ASSERT 1
#endif

#if WE_HAVE_STATIC_ASSERT
    _Static_assert(0, "Test");
#endif

此代码在 gcc 和 clang 上都适用于我:https://godbolt.org/z/svaYjWj4j

最终编辑(我认为):这为我最初关于如何检测_Static_assert 是否可用的问题提供了答案。它还提供了一个备用选项,该选项会在我测试的大多数编译器中产生相对有用的错误。

这里是测试代码的链接:https://godbolt.org/z/TYEj7Tezd

    // Check if we can use built-in _Static_assert
    #if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
        #define MY_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
    
    #else // We make our own
        // MY_JOIN macro trick generates a unique token
        #define MY_JOIN2(pre, post) MY_JOIN3(pre, post)
        #define MY_JOIN3(pre, post) pre ## post
    
        #if defined( __COUNTER__ ) // try to do it the smart way...
            #define MY_JOIN(pre) MY_JOIN2(pre, __COUNTER__)
            #define MY_STATIC_ASSERT(cond, msg) \
            static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
    
        #else // we did our best... 
        //will break if static assert on same line in different file
            #define MY_JOIN(pre) MY_JOIN2(pre, __LINE__)
            #define MY_STATIC_ASSERT(cond, msg) \
            static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
        #endif
    #endif
    
    /* - CHANGE CODE HERE TO TEST THE ASSERTIONS - */
    enum {
        A = 3,
        B = 3,
        C = B - A
    };
    /* - --------------------------------------- - */
    
    // Test to see if the enum values match our assertions
    MY_STATIC_ASSERT(B > A, "B must be greater than A");
    MY_STATIC_ASSERT(C > 0, "C must be greater than zero");

我用来制作这个的有用信息来自这些链接:

http://jonjagger.blogspot.com/2017/07/compile-time-assertions-in-c.html

https://www.tutorialspoint.com/cprogramming/c_preprocessors.htm

https://stackoverflow.com/a/43990067/16292858

【问题讨论】:

  • 如果您使用-std=c99 编译,则无法测试__STDC_VERSION__ >= 201112L。由于_Static_assert 是一个关键字,即使static_assert 宏不可用

标签: c c-preprocessor static-assert


【解决方案1】:

如何测试 _Static_assert 是否已定义?

_Static_assert 是 C11 的一部分。所以检查 C11。

#if __STDC_VERSION__ > 201112L

您也可以#include <assert.h> 并检查#ifdef static_assert

我对@9​​87654327@ 的第一次谷歌搜索有一个很好的例子:如何处理不同的工具和编译器:https://github.com/wc-duck/dbgtools/blob/master/include/dbgtools/static_assert.h#L68


如果您想编写 C11 兼容层并在代码中使用静态断言,例如 use this answer 并回退到您自己的包装器:

// static_assert.h
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond) \
    typedef struct { int static_assertion_failed : !!(cond); } \
        CTASTR(static_assertion_failed_,__COUNTER__)

#include <assert.h>
#ifndef static_assert
#define static_assert(expr, str)  STATIC_ASSERT(expr)
#endif

// somefile.c
#include <static_assert.h>
static_assert(something == something, "Uwu");

【讨论】:

  • 感谢您的提示。我不能使用宏版本,因为我断言枚举中定义的值是有意义的。如果我没记错的话,枚举会在预处理器运行后进行解析和评估。但是能够测试内置编译器版本是否存在是非常有帮助的。我绝对可以使用该链接。感谢您的宝贵时间。
  • 我不明白你的评论。我没有看到从“检查是否支持 _Static_assert”到“断言某些枚举值有意义”的链接。
  • 例如:enum some_constants { A = 5, B = 3, C = A - B }; _Static_assert(B &gt; 0, "B must be greater than zero"); _Static_assert(A &gt; B, "A must be greater than B"); 在这种情况下,我有一些必须作为常量表达式计算的常量值。例如,也许我需要使用这些值来定义某些数组的大小。我需要确保 C 在其值基于 A 和 B 时保持为正。如果我没记错的话,我不能在编译时使用宏来断言这些值。内置 _Static_assert() 适用于这种情况。
  • @pa-mims:确实你不能在预处理过程中评估enum 常量,但这不是“后备”代码所做的。如果断言表达式的计算结果为零,则宏将static_assert 扩展为将违反约束的代码(带有声明符的零宽度位域)。约束在编译器传递中检查,而不是在预处理器中检查,因此enum 常量的值可供它使用。您不会收到很好的消息,但可以保证得到诊断。因此,我怀疑您毕竟可以使用它。
  • Seems like you don't understand for some reason that I can't use a macro-defined static assert for my case 没错,我不明白,我也不明白原因。您可以使用宏定义的静态断言来静态检查枚举值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 2017-04-21
  • 2015-11-22
  • 2018-03-10
相关资源
最近更新 更多