定义一个带参数的宏
01.#define MACRO_P(A) \

02.{ \

03.    some.a = A; \

04.    some.b = A+1; \

05.    some.c[A] = 0; \

06.}

07./* 用法,参数约定为只能是整型常量,范围在0..50 */

08.MACRO_P(0);

09.MACRO_P(33);
复制代码其中参数A使用时必为常量,且在0..50范围内。那么如何在编译时判断越界并报错停止编译,而不是在运行时?
有可能实现吗?如果换成C++呢?

公开答案,其实就是用static_assert方法,这个方法是D语言最早官方支持,当然C和C++也都实现了,能保证程序的正确性并且没有运行时开销:
1. C_1x标准提供了_Static_assert()。gcc 4.6以后开始支持。
文件s.c
01./* C_1x standard _Static_assert version */

02.#include <stdio.h>

03.#define R 50

04.#define M(A)                \

05.{                        \

06._Static_assert( A>=0 && A<=R, "in M(A) A out of range" ); \

07.        s.a = A;        \

08.        s.b = A+1;        \

09.        s.c[A] = 0;        \

10.}

11.typedef struct {

12.        int a;

13.        int b;

14.        int c[R+1];

15.} s_t;

16.s_t s;

17.int main(int argc, char ** argv)

18.{

19.        int i=0;

20.        M(51);

21.        M(i);

22.        return 0;

23.}

24.

25./* compile time error message:

26.$ gcc -o s s.c

27.s.c: In function ‘main’:

28.s.c:20:2: error: static assertion failed: "in M(A) A out of range"

29.s.c:21:2: error: expression in static assertion is not constant

30.$

31.*/
复制代码2.一个不完美的数组下标不能为负的方案,ANSI C实现。
文件:a.c
01./* ANSI C version */

02.#include <stdio.h>

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

04.#define R 50

05.#define M(A)                \

06.{                        \

07.STATIC_ASSERT( A>=0 && A<=R, in_M_A_out_of_range ); \

08.        s.a = A;        \

09.        s.b = A+1;        \

10.        s.c[A] = 0;        \

11.}

12.typedef struct {

13.        int a;

14.        int b;

15.        int c[R+1];

16.} s_t;

17.s_t s;

18.int main(int argc, char ** argv)

19.{

20.        int i=0;

21.        M(51);

22.        M(i);

23.        return 0;

24.}

25.

26./* compile time error message:

27.$ gcc -o a a.c

28.a.c: In function ‘main’:

29.a.c:21:1: error: size of array ‘static_assertion_in_M_A_out_of_range’ is negative

30.$

31.不完美,变量i作参数没有报错,原因是C99支持

32.

33.Z:\>cl a.c

34.Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86

35.Copyright (C) Microsoft Corporation.  All rights reserved.

36.

37.a.c

38.a.c(21) : error C2118: negative subscript

39.a.c(22) : error C2057: expected constant expression

40.a.c(22) : error C2466: cannot allocate an array of constant size 0

41.

42.Z:\>

43.msvc由于不支持C99,反而能找到第二个问题。

44.*/
复制代码3. 利用gcc扩展的实现
文件:n.c
01./* GCC version */

02.#include <stdio.h>

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

04.#define R 50

05.#define M(A)                \

06.{                        \

07.CTC( A>=0 && A<=R ); \

08.        s.a = A;        \

09.        s.b = A+1;        \

10.        s.c[A] = 0;        \

11.}

12.typedef struct {

13.        int a;

14.        int b;

15.        int c[R+1];

16.} s_t;

17.s_t s;

18.int main(int argc, char ** argv)

19.{

20.        int i=0;

21.        M(51);

22.        M(i);

23.        return 0;

24.}

25.

26./* compile time error message:

27.$ gcc -o n n.c

28.n.c: In function ‘main’:

29.n.c:21:2: error: call to ‘compile_time_check’ declared with attribute error: assertion failure: 'i>=0 && i<=R' not true

30.n.c:22:2: error: call to ‘compile_time_check’ declared with attribute error: assertion failure: 'i>=0 && i<=R' not true

31.$

32.*/
复制代码4.利用位域的C实现,但用了__COUNTER__
01./* ANSI C version 2 */

02.#include <stdio.h>

03.#define CTASTR2(pre,post) pre ## post

04.#define CTASTR(pre,post) CTASTR2(pre,post)

05.#define STATIC_ASSERT(cond,msg) \

06.    typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \

07.        CTASTR(static_assertion_failed_,__COUNTER__)

08.#define R 50

09.#define M(A)                \

10.{                        \

11.STATIC_ASSERT( A>=0 && A<=R, in_M_A_out_of_range ); \

12.        s.a = A;        \

13.        s.b = A+1;        \

14.        s.c[A] = 0;        \

15.}

16.typedef struct {

17.        int a;

18.        int b;

19.        int c[R+1];

20.} s_t;

21.s_t s;

22.int main(int argc, char ** argv)

23.{

24.        int i=0;

25.        M(51);

26.        M(i);

27.        return 0;

28.}

29.

30./* compile time error message:

31.$ gcc -o b b.c

32.b.c: In function ‘main’:

33.b.c:25:2: error: zero width for bit-field ‘static_assertion_failed_in_M_A_out_of_range’

34.b.c:26:2: error: bit-field ‘static_assertion_failed_in_M_A_out_of_range’ width not an integer constant

35.$

36.

37.Z:\>cl b.c

38.Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86

39.Copyright (C) Microsoft Corporation.  All rights reserved.

40.

41.b.c

42.b.c(25) : error C2149: 'static_assertion_failed_in_M_A_out_of_range' : named bit

43.field cannot have zero width

44.b.c(26) : error C2057: expected constant expression

45.b.c(26) : error C2149: 'static_assertion_failed_in_M_A_out_of_range' : named bit

46.field cannot have zero width

47.

48.Z:\>

49.*/
复制代码