- 论坛徽章:
- 0
|
本帖最后由 没本 于 2012-02-01 18:45 编辑
定义一个带参数的宏
- #define MACRO_P(A) \
- { \
- some.a = A; \
- some.b = A+1; \
- some.c[A] = 0; \
- }
- /* 用法,参数约定为只能是整型常量,范围在0..50 */
- MACRO_P(0);
- MACRO_P(33);
复制代码 其中参数A使用时必为常量,且在0..50范围内。那么如何在编译时判断越界并报错停止编译,而不是在运行时?
有可能实现吗?如果换成C++呢?
公开答案,其实就是用static_assert方法,这个方法是D语言最早官方支持,当然C和C++也都实现了,能保证程序的正确性并且没有运行时开销:
1. C_1x标准提供了_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
- $
- */
复制代码 2.一个不完美的数组下标不能为负的方案,ANSI C实现。
文件: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作参数没有报错,原因是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,反而能找到第二个问题。
- */
复制代码 3. 利用gcc扩展的实现
文件: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
- $
- */
复制代码 4.利用位域的C实现,但用了__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:\>
- */
复制代码 |
|