天天看點

C語言帶常量參數宏的編譯時參數檢查,有辦法實作嗎

定義一個帶參數的宏

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 */

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

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 */

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

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

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 */

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.$

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.*/

複制代碼

本文轉自 wws5201985 51CTO部落格,原文連結:http://blog.51cto.com/wws5201985/772303,如需轉載請自行聯系原作者

繼續閱讀