有意思,我一直没注意到这点。
在读LCC的第二章时,一开始就遇到了这么两个宏:
alloc.c
#define NEW(p,a) ((p) = allocate(sizeof *(p), (a)))
#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
#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运算符的特殊性:它所接收的参数并不会被实际求值,而是由编译器判断出参数的表达式的类型后直接换算成常量。
既然不被求值,sizeof参数的表达式中的任何副作用也就不会发生。(不定长数组作为参数的例外)
根据
ISO/IEC 9899:1999,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),则该参数会被计算;除此之外其它类型的表达式都不会被计算。“不定长数组”的例子如下:
引用
#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;
}
"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.
分享到:
相关推荐
1.sizeof是运算符,跟加减乘除的性质其实是一样的,在编译的时候进行执行,而不是在运行时才执行。... }输入结果为 1 1sizeof中的++i 的副作用并没有显示出来,原因只可能有一个,在编译的时候sizeo
在实际编程中,我们还需要注意运算符的副作用,比如自增和自减运算符在前缀和后缀形式下的不同行为,以及运算符重载的概念,这允许我们为自定义数据类型定制运算符的行为。 此外,条件运算符(?:)是一种特殊的三目...
`, `~`, `++`, `--`, `+`, `-`, `&`, 和 `*`,以及类型转换运算符 `(type)` 和 `sizeof`。这些运算符通常在其他运算符之前进行计算。值得注意的是,一元运算符`+`和`-`的优先级高于它们的二元形式,这可能导致初学者...
使用运算符时还需要注意可能发生的类型提升、整数提升以及表达式的副作用,例如自增和自减运算符可能会改变其它表达式的计算结果。 此外,C语言支持宏定义,宏定义允许用一个标识符来表示一个常量或者表达式,例如#...
此外,重载运算符不应过于复杂,避免引入不必要的副作用和难以理解的行为。保持运算符的语义清晰,是编写高质量C++代码的关键。 总结,C++的运算符重载是一个强大的工具,但同时也需要谨慎使用。理解何时以及如何...
在C语言中,表达式和语句都可能引起副作用,即除了求值之外的其他影响,如改变变量的值、输入输出操作等。C语言的函数printf()就是利用副作用来工作的,其主要目的是输出信息到标准输出流。 类型转换是C语言中的一...
3. **边际效应**:`#define` 在预处理阶段只是简单的文本替换,可能导致未预料到的副作用,例如宏定义中的参数在多个上下文中使用时可能会出现错误。 #### 五、代码示例解析 考虑以下代码片段: ```c++ #include ...
这在编写涉及复杂表达式的程序时尤其重要,因为它可以帮助避免意外的副作用。 总之,`sizeof`运算符在C++中是一个静态操作,它不依赖于运行时的值,而是基于编译时的信息来确定类型大小。因此,对于`sizeof(i++)`...
6. **sizeof运算符**:`sizeof`是C/C++中的一个运算符,用于返回类型或变量的大小(以字节为单位)。在题目中,`min(-1, sizeof(int))`和`max(-1, sizeof(int))`展示了`sizeof`返回的是无符号整数,因此-1在与无符号...
7. `typedef`和`#define`都可以用于创建类型别名,但`typedef`更安全,因为它在编译时处理,而`#define`进行文本替换可能导致意外的副作用。 8. 表达式分析: - `(A)`:a += (a++) 结果是10,因为a先自增再参与...
2. **sizeof运算符** `sizeof`运算符用于计算变量或数据类型的大小。在`Func(char str[100])`函数中,`str`作为参数传入时,仅相当于一个指向字符的指针,其大小为4字节(假设在32位Windows NT环境下)。同样,动态...
通过不同形式的预增和后增操作,学生可以学习到运算符的优先级和副作用。 此外,实验还让学生尝试修改代码,观察不同运算符顺序对结果的影响,比如将`m=i++;n=++j;`改为`m=++i;n=j++;`或`main(){int i,j;i=8;j=10;...
- **求值顺序(Order of Evaluation)**:包括副作用和计算顺序,通常遵循运算符优先级,但某些情况可能依赖于实现。 以上只是《GNU C 参考手册》中部分核心概念的概述,实际上,手册还详细介绍了各种控制流语句、...
4. **sizeof运算符**: `sizeof`用于计算变量或类型占用的字节数。在函数内部,如果传递的是数组,实际上会退化为指针,所以`sizeof(str)`会返回指针的大小,而不是数组的长度。正确的获取数组长度的方式是`sizeof...
2. **sizeof运算符的理解**: - 在函数`Func(char str[100])`中,`sizeof(str)`的结果是4,因为在函数内部,str被视为指针,32位系统中指针占用4字节。 - 动态分配的内存`void *p = malloc(100);`,`sizeof(p)`的...
另外,sizeof运算符不会使数组退化为指针,这是其与strlen的区别之一。 static关键字在C和C++中有所区别。在C中,static用于局部静态变量、外部静态变量和函数,而在C++中,它还可以用于定义类的静态成员变量和函数...
运算符如自增(++)和自减(--)是C语言的特色,可以简化代码,但也需要注意潜在的副作用。例如,使用i++或p--时,应避免产生二义性,必要时使用括号来确保清晰性。在表达式中,不同类型的数值和字符数据可以混合...
2. sizeof运算符的理解: - sizeof用于计算数据类型的大小或变量所占内存字节数。在32位系统中,字符串常量的长度包括结束符'\0',因此sizeof(str) = 25(包括空字符),指针p的大小通常为4字节,整型变量n的大小也...