sizeof运算符与副作用

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

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

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

另外写了两个测试,
第一个,把LCC里的NEW宏简化,只观察sizeof与副作用的关系
test_macro_sideeffect.c
#include <stdio.h>

#define FOO(x) (*(x) = sizeof *(x))

void main( int argc, char* argv[] ) {
int array[4] = { 0 };
int* ptr = array;
FOO( ptr++ );
printf( "%d, %d, %d, %d\n", array[0], array[1], array[2], array[3] );
printf( "%x, %x\n", array, ptr );
}

/* output w/VC8:
4, 0, 0, 0
13ff5c, 13ff60
*/


第二个,不用宏,直接把sizeof放在表达式里:
#include <stdio.h>

void main( int argc, char* argv[] ) {
int array[4] = { 40, 30, 20, 10 };
int* ptr = array;
sizeof ((*(ptr++))++);
printf( "%d, %d, %d, %d\n", array[0], array[1], array[2], array[3] );
printf( "%x, %x\n", array, ptr );
}

/* output w/VC8:
40, 30, 20, 10
13ff5c, 13ff5c
*/


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

根据[url=http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf]ISO/IEC 9899:1999[/url],6.5.3.4 The [b]sizeof[/b] operator:
[quote]The [b]sizeof[/b] 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.[/quote]
如果sizeof运算符的参数是一个不定长数组(variable length array),则该参数会被计算;除此之外其它类型的表达式都不会被计算。“不定长数组”的例子如下:
[quote]
#include <stddef.h>

size_t fsize3(int n)
{
char b[n+3]; // variable length array
return sizeof b; // execution time sizeof
}

int main()
{
size_t size;
size = fsize3(10); // fsize3 returns 13
return 0;
}
[/quote]
"Variable length array"(VLA)到底怎么翻我抓不太准。“可变长数组”或者“不定长数组”似乎都可以,但又都有点模糊。这里我选择了后者。
关于VLA的具体规定请参照规范中的6.7.5.2节:
[quote]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.[/quote]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值