Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1242024
  • 博文数量: 510
  • 博客积分: 20296
  • 博客等级: 上将
  • 技术积分: 4680
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-30 03:58
文章存档

2011年(13)

2010年(92)

2009年(242)

2008年(163)

我的朋友

分类: C/C++

2009-01-26 14:31:05

有意思,我一直没注意到这点。
在读LCC的第二章时,一开始就遇到了这么两个宏:
alloc.c
C代码
  1. #define NEW(p,a) ((p) = allocate(sizeof *(p), (a)))   
  2. #define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p))  

书上特别说明了:
引用
注意,NEW和NEW0对p都只计算一次,所以,调用这两个宏时,即使传递的参数表达式有副作用也无妨,如NEW(a[i++])。


可是作为参数的p确实在赋值的两边各出现了一次,为什么p只计算了一次呢?

另外写了两个测试,
第一个,把LCC里的NEW宏简化,只观察sizeof与副作用的关系
test_macro_sideeffect.c
C代码
  1. #include    
  2.   
  3. #define FOO(x) (*(x) = sizeof *(x))   
  4.   
  5. void main( int argc, char* argv[] ) {   
  6.     int array[4] = { 0 };   
  7.     int* ptr = array;   
  8.     FOO( ptr++ );   
  9.     printf( "%d, %d, %d, %d\n", array[0], array[1], array[2], array[3] );   
  10.     printf( "%x, %x\n", array, ptr );   
  11. }   
  12.   
  13. /* output w/VC8:  
  14. 4, 0, 0, 0  
  15. 13ff5c, 13ff60  
  16. */  

第二个,不用宏,直接把sizeof放在表达式里:
C代码
  1. #include    
  2.   
  3. void main( int argc, char* argv[] ) {   
  4.     int array[4] = { 40, 30, 20, 10 };   
  5.     int* ptr = array;   
  6.     sizeof ((*(ptr++))++);   
  7.     printf( "%d, %d, %d, %d\n", array[0], array[1], array[2], array[3] );   
  8.     printf( "%x, %x\n", array, ptr );   
  9. }   
  10.   
  11. /* output w/VC8:  
  12. 40, 30, 20, 10  
  13. 13ff5c, 13ff5c  
  14. */  

可以看到LCC里的NEW宏中p之所以只被计算了一次,并不是因为宏的特殊性,而是因为sizeof运算符的特殊性:它所接收的参数并不会被实际求值,而是由编译器判断出参数的表达式的类型后直接换算成常量。
既然不被求值,sizeof参数的表达式中的任何副作用也就不会发生。(不定长数组作为参数的例外)

根据,6.5.3.4 The sizeof operator:
引用
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

如果sizeof运算符的参数是一个不定长数组(variable length array),则该参数会被计算;除此之外其它类型的表达式都不会被计算。“不定长数组”的例子如下:
引用
C代码
  1. #include    
  2.   
  3. size_t fsize3(int n)   
  4. {   
  5.     char b[n+3]; // variable length array   
  6.     return sizeof b; // execution time sizeof   
  7. }   
  8.   
  9. int main()   
  10. {   
  11.     size_t size;   
  12.     size = fsize3(10); // fsize3 returns 13   
  13.     return 0;   
  14. }  

"Variable length array"(VLA)到底怎么翻我抓不太准。“可变长数组”或者“不定长数组”似乎都可以,但又都有点模糊。这里我选择了后者。
关于VLA的具体规定请参照规范中的6.7.5.2节:
引用
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecfied size, which can only be used in declarations with function prototype scope; such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
阅读(845) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~