- 論壇徽章:
- 0
|
本帖最后由 沒本 于 2012-02-01 18:45 編輯
定義一個帶參數(shù)的宏
- #define MACRO_P(A) \
- { \
- some.a = A; \
- some.b = A+1; \
- some.c[A] = 0; \
- }
- /* 用法,參數(shù)約定為只能是整型常量,范圍在0..50 */
- MACRO_P(0);
- MACRO_P(33);
復(fù)制代碼 其中參數(shù)A使用時必為常量,且在0..50范圍內(nèi)。那么如何在編譯時判斷越界并報錯停止編譯,而不是在運行時?
有可能實現(xiàn)嗎?如果換成C++呢?
公開答案,其實就是用static_assert方法,這個方法是D語言最早官方支持,當(dāng)然C和C++也都實現(xiàn)了,能保證程序的正確性并且沒有運行時開銷:
1. C_1x標(biāo)準(zhǔn)提供了_Static_assert()。gcc 4.6以后開始支持。
文件s.c
- /* C_1x standard _Static_assert version */
- #include <stdio.h>
- #define R 50
- #define M(A) \
- { \
- _Static_assert( A>=0 && A<=R, "in M(A) A out of range" ); \
- s.a = A; \
- s.b = A+1; \
- s.c[A] = 0; \
- }
- typedef struct {
- int a;
- int b;
- int c[R+1];
- } s_t;
- s_t s;
- int main(int argc, char ** argv)
- {
- int i=0;
- M(51);
- M(i);
- return 0;
- }
- /* compile time error message:
- $ gcc -o s s.c
- s.c: In function ‘main’:
- s.c:20:2: error: static assertion failed: "in M(A) A out of range"
- s.c:21:2: error: expression in static assertion is not constant
- $
- */
復(fù)制代碼 2.一個不完美的數(shù)組下標(biāo)不能為負(fù)的方案,ANSI C實現(xiàn)。
文件:a.c
- /* ANSI C version */
- #include <stdio.h>
- #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
- #define R 50
- #define M(A) \
- { \
- STATIC_ASSERT( A>=0 && A<=R, in_M_A_out_of_range ); \
- s.a = A; \
- s.b = A+1; \
- s.c[A] = 0; \
- }
- typedef struct {
- int a;
- int b;
- int c[R+1];
- } s_t;
- s_t s;
- int main(int argc, char ** argv)
- {
- int i=0;
- M(51);
- M(i);
- return 0;
- }
- /* compile time error message:
- $ gcc -o a a.c
- a.c: In function ‘main’:
- a.c:21:1: error: size of array ‘static_assertion_in_M_A_out_of_range’ is negative
- $
- 不完美,變量i作參數(shù)沒有報錯,原因是C99支持
- Z:\>cl a.c
- Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
- Copyright (C) Microsoft Corporation. All rights reserved.
- a.c
- a.c(21) : error C2118: negative subscript
- a.c(22) : error C2057: expected constant expression
- a.c(22) : error C2466: cannot allocate an array of constant size 0
- Z:\>
- msvc由于不支持C99,反而能找到第二個問題。
- */
復(fù)制代碼 3. 利用gcc擴展的實現(xiàn)
文件:n.c
- /* GCC version */
- #include <stdio.h>
- #define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })
- #define R 50
- #define M(A) \
- { \
- CTC( A>=0 && A<=R ); \
- s.a = A; \
- s.b = A+1; \
- s.c[A] = 0; \
- }
- typedef struct {
- int a;
- int b;
- int c[R+1];
- } s_t;
- s_t s;
- int main(int argc, char ** argv)
- {
- int i=0;
- M(51);
- M(i);
- return 0;
- }
- /* compile time error message:
- $ gcc -o n n.c
- n.c: In function ‘main’:
- n.c:21:2: error: call to ‘compile_time_check’ declared with attribute error: assertion failure: 'i>=0 && i<=R' not true
- n.c:22:2: error: call to ‘compile_time_check’ declared with attribute error: assertion failure: 'i>=0 && i<=R' not true
- $
- */
復(fù)制代碼 4.利用位域的C實現(xiàn),但用了__COUNTER__
- /* ANSI C version 2 */
- #include <stdio.h>
- #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__)
- #define R 50
- #define M(A) \
- { \
- STATIC_ASSERT( A>=0 && A<=R, in_M_A_out_of_range ); \
- s.a = A; \
- s.b = A+1; \
- s.c[A] = 0; \
- }
- typedef struct {
- int a;
- int b;
- int c[R+1];
- } s_t;
- s_t s;
- int main(int argc, char ** argv)
- {
- int i=0;
- M(51);
- M(i);
- return 0;
- }
- /* compile time error message:
- $ gcc -o b b.c
- b.c: In function ‘main’:
- b.c:25:2: error: zero width for bit-field ‘static_assertion_failed_in_M_A_out_of_range’
- b.c:26:2: error: bit-field ‘static_assertion_failed_in_M_A_out_of_range’ width not an integer constant
- $
- Z:\>cl b.c
- Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
- Copyright (C) Microsoft Corporation. All rights reserved.
- b.c
- b.c(25) : error C2149: 'static_assertion_failed_in_M_A_out_of_range' : named bit
- field cannot have zero width
- b.c(26) : error C2057: expected constant expression
- b.c(26) : error C2149: 'static_assertion_failed_in_M_A_out_of_range' : named bit
- field cannot have zero width
- Z:\>
- */
復(fù)制代碼 |
|