C中的静态断言


Answers:


90

C11标准添加了_Static_assert关键字。

这是因为GCC-4.6实现的

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

第一个时隙必须是整数常量表达式。第二个插槽是常量字符串文字,可以是long(_Static_assert(0, L"assertion of doom!"))。

我应该注意,这在clang的最新版本中也已实现。


4
[...似乎由gcc,clang来实现...]您可以更加断言,;-)_Static_assert是C11标准的一部分,任何支持C11的编译器都将拥有它。
PP

1
可以在文件范围(任何功能之外)上使用吗?因为我error: expected declaration specifiers or '...' before 'sizeof'上线了static_assert( sizeof(int) == sizeof(long int), "Error!); (顺便说一句,我使用的是C而不是C ++)
user10607

@ user10607我很惊讶这无法正常工作。等等,您在错误字符串末尾缺少引号。把它放回去。这对我在gcc-4.9上有效:_Static_assert( sizeof(int) == sizeof(long int), "Error!");在我的机器上,我得到了错误。
emsr

我在Ubuntu上有gcc 4.8.2。缺少的报价是一个注释错误(我在代码中有)。这是文件中包含几个头文件之后的第一行。编译器给我两个完全相同的错误:error: expected declaration specifiers or '...' before 'sizeof'AND error: expected declaration specifiers or '...' before string constant(他指的是"Error!"字符串)(另:我正在使用-std = c11进行编译。将声明放入函数中时,所有方法都工作正常(失败并按预期成功))
user10607

2
@ user10607我还必须在命令行上指定-std = gnu11。我真的很惊讶4.8和4.8之间会有区别。我只有一条线的消息来源。我还使用了C标准_Static_assert而不是C ++ ish static_assert。您需要`#include <assert.h>来获取static_assert宏。
emsr 2014年

92

这在功能和非功能范围内有效(但在结构,联合内部无效)。

#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); 
}
  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]它,即使在生锈的老式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); 
}

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()
{
}

这是这样的:

$ 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

1
在Visual Studio中,它只说“负下标”,没有提及变量名...
szx 2012年

北欧大型机-答案中的选项3在clang上不起作用。
Elazar 2013年

1
关于最后一个(特定于GCC 4.3+的)解决方案:此功能非常强大,因为它可以检查优化器可以确定的所有内容,但是如果未启用优化则失败。最低限度的最低优化水平(-Og)通常足以满足要求,并且不应干扰调试。如果未定义__OPTIMIZE__(和__GNUC__),则可以考虑使静态断言成为no-op或运行时断言。
索伦Løvborg

在具有LINE版本的代码段中(更新:为了完整性起见,这是具有LINE的版本),在编译时,它在行(STATIC_ASSERT(X,static_assertion_at_line _ ## L))处出错,可以通过添加一个来更正级别如下:#define COMPILE_TIME_ASSERT4(X,L)static_assert(X,#L); #define COMPILE_TIME_ASSERT3(X,L)COMPILE_TIME_ASSERT3(X,“”在以下位置断言:## L“”);
sundar

我使用类似于__LINE__gcc 4.1.1中的版本的方法... ...当两个不同的标头恰好在同一编号行上有一个标头时,有时会感到烦恼!
MM

10

CL

我知道这个问题明确提到了gcc,但是为了完整起见,这是针对Microsoft编译器的一项调整。

使用负大小的数组typedef不能说服cl吐出体面的错误。它只是说error C2118: negative subscript。在这方面,零宽度的位域效果更好。由于这涉及到对结构的typedeffing,因此我们确实需要使用唯一的类型名。__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__)

现在

STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)

cl给出:

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

Gcc还给出了清晰的信息:

错误:位域“ static_assertion_failed_use_another_compiler_luke”的宽度为零


4

维基百科

#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}

COMPILE_TIME_ASSERT( BOOLEAN CONDITION );

15
如果您链接到真实来源,则更好:jaggersoft.com/pubs/CVu11_3.html
Matt Joiner 2010年

它在gcc 4.6中不起作用-它说“ case label不能减少为整数常量”。有一点。
利桑

你们到现在都可能已经开始前进了,但是我最终写了自己的(请参阅答案)。我使用了您的链接@MattJoiner来帮助我
Hashbrown 2014年

如果您可以打扰,请告诉我@Liosan是否适合您。我才刚刚开始研究C ++,所以我来参加聚会很晚
Hashbrown

对于Visual C ++,自2010版以来,它内置了static_assert,并且可以在c ++和c模式下使用。但是,它没有内置的c99 _Static_assert。
ddbug

3

我会 建议通过以下方式使用解决方案typedef

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

数组声明与 typedef不保证关键字在编译时会求值。例如,以下代码将在块作用域内进行编译:

int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);

我建议改用(在C99上):

#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]

由于有static关键字,该数组将在编译时定义。请注意,此断言仅COND在编译时与之一起使用。它不能基于内存中的值(例如分配给变量的值)使用(即,编译将失败)。


4
尽管这可行,但也会增加您的内存需求。
sherrellbc

1
错误:“ static_assertion_INVALID_CHAR_SIZE”已定义但未使用[-Werror = unused-variable]
Alex

2

如果将STATIC_ASSERT()宏与一起使用__LINE__,则可以通过在.c文件中的条目与头文件中的其他条目之间避免行号冲突__INCLUDE_LEVEL__

例如 :

/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y )      BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y )   BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y )  X##Y
#define STATIC_ASSERT(x)        typedef char \
        BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
                    BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]

1

经典方法是使用数组:

char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];

之所以起作用,是因为如果断言为true,则数组的大小为1并且有效,但是如果为false,则大小为-1会产生编译错误。

大多数编译器将显示变量的名称,并指向代码的右侧,您可以在其中留下有关断言的最终注释。


将其包装到泛型#define STATIC_ASSERT()类型宏中,并使用泛型示例提供更多的泛型示例和示例编译器输出,STATIC_ASSERT()将会给您带来更多的赞誉,并使这种技术更有意义。
加布里埃尔·斯台普斯

我不同意 编译器会看到思想宏,并给出更混乱的消息。
Paolo.Bolzoni

1

在Perl中,特别是perl.h3455行<assert.h>已预先包括在内):

/* STATIC_ASSERT_DECL/STATIC_ASSERT_STMT are like assert(), but for compile
   time invariants. That is, their argument must be a constant expression that
   can be verified by the compiler. This expression can contain anything that's
   known to the compiler, e.g. #define constants, enums, or sizeof (...). If
   the expression evaluates to 0, compilation fails.
   Because they generate no runtime code (i.e.  their use is "free"), they're
   always active, even under non-DEBUGGING builds.
   STATIC_ASSERT_DECL expands to a declaration and is suitable for use at
   file scope (outside of any function).
   STATIC_ASSERT_STMT expands to a statement and is suitable for use inside a
   function.
*/
#if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
/* static_assert is a macro defined in <assert.h> in C11 or a compiler
   builtin in C++11.  But IBM XL C V11 does not support _Static_assert, no
   matter what <assert.h> says.
*/
#  define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
#else
/* We use a bit-field instead of an array because gcc accepts
   'typedef char x[n]' where n is not a compile-time constant.
   We want to enforce constantness.
*/
#  define STATIC_ASSERT_2(COND, SUFFIX) \
    typedef struct { \
        unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
    } _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#  define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#  define STATIC_ASSERT_DECL(COND)    STATIC_ASSERT_1(COND, __LINE__)
#endif
/* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
   error (static_assert is a declaration, and only statements can have labels).
*/
#define STATIC_ASSERT_STMT(COND)      STMT_START { STATIC_ASSERT_DECL(COND); } STMT_END

如果static_assert可用(来自<assert.h>),则使用它。否则,如果条件为假,则声明一个负大小的位字段,这将导致编译失败。

STMT_START/STMT_END是分别扩展到do/的宏while (0)


1

因为:

  1. _Static_assert() 现在在gcc中为所有C版本定义了,并且
  2. static_assert() 在C ++ 11及更高版本中定义

因此,以下简单宏STATIC_ASSERT()适用于:

  1. C ++:
    1. C ++ 11(g++ -std=c++11)或更高版本
  2. C:
    1. gcc -std=c90
    2. gcc -std=c99
    3. gcc -std=c11
    4. gcc (未指定标准)

定义STATIC_ASSERT如下:

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")

现在使用它:

STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed" 

例子:

在Ubuntu上使用gcc 4.8.4进行了测试:

示例1:良好的gcc输出(即:STATIC_ASSERT()代码有效,但条件为false,导致编译时断言):

$ gcc -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c:在函数“ main”中
static_assert.c:78:38:错误:静态断言失败:“(1> 2)失败”
#define STATIC_ASSERT(test_for_true )_Static_assert((test_for_true),“(” #test_for_true“)失败”)
^
static_assert.c:88:5:注意:在宏'
STATIC_ASSERT'STATIC_ASSERT(1> 2)的扩展中;
^

示例2:良好的g++ -std=c++11输出(即:STATIC_ASSERT()代码有效,但条件为假,导致编译时断言):

$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c && ./static_assert
static_assert.c:在函数'int main()'
static_assert.c:74:32:错误:静态声明失败:(1> 2)失败
#define _Static_assert static_assert / *static_assert是C ++ 11或更高版本的一部分* /
^
static_assert.c:78:38:注意:在宏'_Static_assert'的扩展中
#define STATIC_ASSERT(test_for_true)_Static_assert((test_for_true), “(” #test_for_true“)失败”)
^
static_assert.c:88:5:注意:在宏'
STATIC_ASSERT'STATIC_ASSERT(1> 2)的扩展中;
^

示例3: C ++输出失败(即:断言代码根本无法正常工作,因为它使用的是C ++ 11之前的C ++版本):

$ g ++ -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c:88:5:警告:标识符'static_assert'是C ++ 11中的关键字[-Wc ++ 0x-compat]
STATIC_ASSERT(1> 2 );
^
static_assert.c:在函数'int main()'中
static_assert.c:78:99:错误:未在此范围内声明'static_assert'
#define STATIC_ASSERT(test_for_true)_Static_assert((test_for_true),“(” #test_for_true“ )失败“)
^
static_assert.c:88:5:注意:在宏'
STATIC_ASSERT'STATIC_ASSERT(1> 2)的扩展中;
^

完整的测试结果在这里:

/*
static_assert.c
- test static asserts in C and C++ using gcc compiler

Gabriel Staples
4 Mar. 2019 

To be posted in:
1. /programming/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
2. /programming/3385515/static-assert-in-c/7287341#7287341

To compile & run:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert

-------------
TEST RESULTS:
-------------

1. `_Static_assert(false, "1. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  NO

2. `static_assert(false, "2. that was false");` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             NO
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    NO
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    NO
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

3. `STATIC_ASSERT(1 > 2);` works in:
  C:
    gcc -Wall -o static_assert static_assert.c && ./static_assert             YES
    gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert    YES
    gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert    YES
  C++:
    g++ -Wall -o static_assert static_assert.c && ./static_assert             NO
    g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert  NO
    g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert  YES

*/

#include <stdio.h>
#include <stdbool.h>

/* For C++: */
#ifdef __cplusplus
    #ifndef _Static_assert
        #define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
    #endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")


int main(void)
{
    printf("Hello World\n");

    /*_Static_assert(false, "1. that was false");*/
    /*static_assert(false, "2. that was false");*/

    STATIC_ASSERT(1 > 2);

    return 0;
}

有关:

  1. 使用static_assert检查传递给宏的类型[我自己的答案]
    1. https://en.cppreference.com/w/cpp/types/is_same
    2. https://en.cppreference.com/w/cpp/language/decltype
  2. 使用static_assert检查传递给宏的类型
  3. 如何在C中使用静态断言来检查传递给宏的参数的类型

1
当其中有static_assert宏时,为什么如此复杂assert.h
再见SE

@KamiKaze,您的问题让我感到惊讶,因为您似乎还没有真正阅读我的答案?我的答案的第二行说明了所有问题:“ static_assert()在C ++ 11和更高版本中定义”。因此,static_assert()在C语言中根本无法使用。另请参见:en.cppreference.com/w/cpp/language/static_assert-它显示static_assert存在“(自C ++ 11起)”。我的回答的妙处在于,它可以在gcc的C90和更高版本以及任何C ++ 11和更高版本中运行,而不仅仅是在C ++ 11和更高版本中(如)static_assert()。另外,我的答案有什么复杂之处?只有几#define秒钟。
加布里埃尔·斯台普斯

static_assert从C11开始在C中定义。它是一个扩展为的宏_Static_assertzh.cppreference.com/w/c/error/static_assert。另外,与您的答案形成对比的_Static_assert在gcc的c99和c90中不可用(仅在gnu99和gnu90中)。这符合标准。基本上,您需要做很多额外的工作,只有在使用gnu90和gnu99进行编译时才会带来好处,并且使实际用例很小。
再见SE

>“ _Static_assert在gcc的c99和c90中不可用(仅在gnu99和gnu90中)”。我明白你的意思了。这是gcc扩展名,所以您是正确的。>“基本上,您需要做很多额外的工作”。我不同意; 2个极其简单的定义绝不是“很多”的额外工作。话虽如此,我明白你的意思了。我仍然认为我所做的事情是有用的,并且可以为此处提供的知识和答案增加价值,因此我认为这不应该被否决。另外,我在说“ C90和更高版本”而不是“ gcc C90和更高版本”或“ g90和更高版本”时出错,只是在我上面的评论中,而不是我的回答中。
加布里埃尔·斯台普斯

由于事实是错误的,因此赞成票是合理的。如果您更正了错误的陈述,我将再次检查答案,并可能撤消我的反对票。如果没有必要,仍然添加这样的代码(因此,如果您不使用gnu90和gnu99),这样做就不那么有益了,而且会增加混乱。如果您有用例,那可能是值得的。但是我不知道需要gnu99 / 90和c ++ 11兼容性的用例是否稀有。
再见SE

0

对于那些想要真正基本且可移植但又无法访问C ++ 11功能的人,我已经写了东西。正常
使用STATIC_ASSERT(如果需要,可以在同一函数中编写两次),然后GLOBAL_STATIC_ASSERT在函数外部使用唯一短语作为第一个参数。

#if defined(static_assert)
#   define STATIC_ASSERT static_assert
#   define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
#   define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
#   define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif

GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");

int main(int c, char** v) {
    (void)c; (void)v;
    STATIC_ASSERT(1 > 0, "yo");
    STATIC_ASSERT(1 > 0, "yo");
//    STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
    return 0;
}

说明:
首先,它检查您是否有真实的断言,如果有的话,您肯定要使用它。
如果您不这样做,则通过获取pred冰糖并单独对其进行断言。这有两件事。
如果为零,则表示断言失败,它将导致被零除的错误(该算术是强制的,因为它试图声明一个数组)。
如果不为零,则将数组大小标准化为1。因此,如果断言通过,则无论如何您都不希望它失败,因为您的谓词评估为-1(无效)或为232442(大量空间浪费,如果可以优化则IDK)。
因为STATIC_ASSERT用大括号括起来,这使其成为一个块,从而对变量进行范围划分assert,这意味着您可以多次编写。
它还将其强制转换为void,这是摆脱unused variable警告的一种已知方法。
对于GLOBAL_STATIC_ASSERT,它不是在代码块中,而是生成一个名称空间。允许在函数外部使用命名空间。unique如果多次使用该标识符,则必须使用标识符来停止任何冲突的定义。


在GCC和VS'12 C ++上为我工作


2
有在C没有命名空间
martinkunev

啊,哎呀,看错了问题。看来我还是来这里寻找C ++的答案(看我答案的最后一行),所以我将其留在这里以防其他人也这样做
Hashbrown

0

这可以通过设置“删除未使用的”选项来实现。我可能会使用一个全局函数来检查全局参数。

//
#ifndef __sassert_h__
#define __sassert_h__

#define _cat(x, y) x##y

#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
    _cat(ASSERT_WARNING_, ln)(); \
}

#define sassert(exp) _sassert(exp, __LINE__)

#endif //__sassert_h__

//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
    sassert(TXB_TX_PKT_SIZE < 3000000);
    sassert(TXB_TX_PKT_SIZE >= 3000000);
    ...
}

//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//

1
如果它可以工作,那么只能在可执行文件的源代码中进行。
编码器

0

这适用于一些旧的gcc。对不起,我忘记了它是什么版本:

#define _cat(x, y) x##y

#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]

#define sassert(exp) _sassert((exp), __LINE__)

//
sassert(1 == 2);

//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134)  main.c  /test/source/controller line 134    C/C++ Problem
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.