sizeof操作符
来源:互联网 发布:淘宝酒类授权怎么写 编辑:程序博客网 时间:2024/05/28 15:08
了解sizeof
sizeof是一元操作符
sizeof是编译时的一元操作符, 返回任意对象所属类型的大小(单位:字节). 值的类型是size_t, 表示无符号整数, 它是个宏, 可以定义为unsigned int或unsigned long.
形式如下:
sizeof(type name);sizeof(expr);sizeof expr;
sizeof中的圆括号不是必须的, 但是一元操作符的优先级高于二元操作符, 表达式sizeof a + b会被编译器误认为sizeof(a) + b. 所以圆括号有时候是必须的.
编译时决定的常量
它的值在编译时确定.
例外情况是: 如果操作数是可变长度的数组类型(c99)
sizeof不计算expr
sizeof(expr)并不计算expr, 而是确定expr的类型, 获取该类型的大小. 所以sizeof(a=b+1)不会改变a的值, 它的结果是a的类型的大小.
struct Stu { char stuno[10]; char name[32];};int main() { printf("%lu\n", (unsigned long)sizeof((struct Stu*)0)->stuno); /* print 10 */ int i = 2; printf("%lu\n", (unsigned long)sizeof(++i)); /* print 4 */ printf("%d\n", i); /* print 2 (i isn't changed)*/ int a = 5; int b = 3; printf("%lu\n", (unsigned long)sizeof(a=b+1)); /* print 4 */ printf("%d\n", a); /* print 5 (a isn't changed)*/ return 0;}
sizeof只关心((struct Stu*)0)->stuno的类型:char[10]
char类型的sizeof值
C标准要求sizeof(char)的值一定是1, 其他类型根据具体实现而定.
对操作数的限制
除了位域、函数名和空表达式, 其他任何值都可以[1](待测试...fix me!).
输出sizeof值
sizeof操作符的值类型为无符号整数类型size_t, size_t可能被定义为unsigned int或unsigned long或unsigned long long(c99), 那么该如何输出呢?
C89中, 可以将size_t强转成unsigned long, 再输出[1]:
printf("%lu\n", (unsigned long)sizeof(int));
C99中, 有专门输出size_t类型的格式"%zu"[1]:
printf("%zu\n", sizeof(int));
常用方法
计算数组的长度
假设有定义int arr[100];那么sizeof(arr)/sizeof(arr[0])可以获取它的长度100, 可以将其定义为宏, 像使用常量一样使用它:
#define ARR_LEN (sizeof(arr)/sizeof(arr[0]))
这种写法要优于:
#define ARR_LEN (sizeof(arr)/sizeof(int))
因为即使需要修改数组arr的类型, 也无需修改该宏.
在strncpy中使用
一般建议使用strncpy函数代替strcpy函数, 防止数组溢出. 假设有字符数组a和b, 现在要将字串b复制到a中, 由于不知道b的长度, 又要保证a不溢出, 所以惯用的方法如下:
strncpy(a, b, sizeof(a) - 1);a[sizeof(a) - 1] = '\0';
获取结构体对象的大小
误用
获取数组的大小
有人写了以下两个函数, 分别用来获取数组所占用的字节数和复制字符数组:
#include <stdio.h>size_t getArrSize(char a[]) { return sizeof(a);}void myCopy(char a[], char b[]) { strncpy(a, b, sizeof(a) - 1); a[sizeof(a) - 1] = '\0';}int main() { char a[100]; char b[50] = "Strong coffee and late nights"; myCopy(a, b); printf("%d\n", (int)getArrSize(a)); /* print 4 (sizeof(char*)) */ printf("%s\n", a); /* print Str */ return 0;}
写这两个函数的人, 在使用sizeof之前, 已经犯了错误:误以为数组可以作为值传递, 传递给形参. 声明size_t getArrSize(char a[])在编译器看来, 无异于size_t getArrSize(char *a), 所以sizeof(a)获取的永远都是sizeof(char*). 使用char a[]的方式, 唯一的作用是给看代码的人提示:实参可能是数组. 对于形参而言, 传递过来的是数组的地址(如果您对获取数组长度感兴趣, 请见另一篇文章:对数组的引用). 类似于myCopy函数中的误用, 我在真实系统的代码见到过, 我给myCopy新增了一个参数iALen用来表示数组a的长度:
void myCopy(char a[], char b[], size_t iALen) { strncpy(a, b, iALen - 1); a[iALen - 1] = '\0';}
to be continue...I'm sleepy...fix me!见谅, 以下内容待修改.
demo
在32位的机器上, 有:
printf("%d\n", sizeof(char)); /* print: 1 */ printf("%d\n", sizeof(short)); /* print: 2 */ printf("%d\n", sizeof(int)); /* print: 4 */ printf("%d\n", sizeof(long)); /* print: 4 */ printf("%d\n", sizeof(float)); /* print: 4 */ printf("%d\n", sizeof(double)); /* print: 8 */ printf("%d\n", sizeof(long double));/* print: 8 */ printf("%d\n", sizeof(string)); /* print: 16 */
1. 若sizeof应用在表达式expr上时, 并未计算表达式的值, 而是计算表达式的类型大小:
int i = 1; double d = 1.2; double d2 = 0.0; printf("%d\n", sizeof(d * i)); /* print: 8 */ printf("%d\n", sizeof(d2 = d * i)); /* print: 8 */ printf("%f\n", d2); /* print: 0.0 */
2. 指针, 则返回指针所占的字节数, 与所指的对象无关:
char c = 'a'; double d = 2.0; char *cptr = &c; char *str = "hello"; double *dptr = &d; double *dptr1; /* wild pointer */ Test *test = new Test();/* Test is a class */ printf("%d\n", sizeof(cptr)); /* print: 4 */ printf("%d\n", sizeof(str)); /* print: 4 */ printf("%d\n", sizeof(dptr)); /* print: 4 */ printf("%d\n", sizeof(dptr1)); /* print: 4 */ printf("%d\n", sizeof(test)); /* print: 4 */
3. 指针所指对象, 返回指针(即使该指针是无效的)所指对象的大小:
char c = 'a'; double d = 2.0; char *cptr = &c; char *str = "hello"; double *dptr = &d; double *dptr1; /* wild pointer */ string *str1 = new string[2]; str1[0] = "hello"; str1[1] = "world"; char *cparry = new char[10]; printf("%d\n", sizeof(*cptr)); /* print: 1 */ printf("%d\n", sizeof(*str)); /* print: 1 */ printf("%d\n", sizeof(*dptr)); /* print: 8 */ printf("%d\n", sizeof(*dptr1)); /* print: 8 */ printf("%d\n", sizeof(*str1)); /* print: 16 */ printf("%d\n", sizeof(str1[1])); /* print: 16 */ printf("%d\n", sizeof(cparry)); /* print: 4 */ printf("%d\n", sizeof(*cparry)); /* print: 1 */
4. 引用, 返回所引用对象的类型的大小:
int i = 1; double d = 3.0; int &refi = i; double &refd = d; printf("%d\n", sizeof(refi)); /* print: 4 */ printf("%d\n", sizeof(refd)); /* print: 8 */5. 数组, 返回数组所占用的内存空间(数组长度 * 数组元素类型大小, 若是字符串, 则最后的'\0'也计算在内):
char carry[] = "hello"; int iarry[20]; string strarry[] = { "hello", "world", "!" }; printf("%d\n", sizeof(carry)); /* print: 6 */ printf("%d\n", sizeof(iarry)); /* print: 80(20 * sizeof(int)) */ printf("%d\n", sizeof(strarry)); /* print: 64(3 * sizeof(string)) */
注意,当数组作为函数参数时, 数组名将被看作指针:
size_t test(char var[]){ return sizeof var;}int main(){ char a[20] = "hello"; printf("%d\n", test(a)); /* print: 4 */ return 0;}
6. 结构类型, 与该类的成员变量有关. 注意, 编译器为了提高性能, 会对数据进行对齐操作(大小为4的倍数):
struct test1{ char ch1; int i; char ch2;};struct test2{ char ch1; char ch2; int i;};struct test3{ int i; char ch1; char ch2;};struct test4{ char ch1; int i; static char ch2;};int main(){ printf("%d\n", sizeof(test1)); /* print: 12 */ printf("%d\n", sizeof(test2)); /* print: 8 */ printf("%d\n", sizeof(test3)); /* print: 8 */ printf("%d\n", sizeof(test4)); /* print: 8 */ return 0;}
在内存中的结构示意图如下:
test1:
|char|--|--|--|
|-----int-----|
|char|--|--|--|
test2:
|char|char|-|-|
|-----int-----|
test3:
|-----int-----|
|char|char|-|-|
test4:
|char|--|--|--|
|-----int-----|
注意, 静态变量是存放在全局数据区中的, 而sizeof计算栈中分配的大小.
另一个例子:
struct test{ float f; char ch; int i[3];};int main(){ printf("%d\n", sizeof(test)); /* print: 20 */ return 0;}内存结构:
|----float----|
|char|--|--|--|
|-----i[0]----|
|-----i[1]----|
|-----i[2]----|
7. 类类型:
class A{};class A1{public: A1() {} ~A1() {}};class A2{public: A2() {} virtual ~A2() {}};class B : public A{};class C : virtual public A{};class D : public A2{};int main(){ printf("%d\n", sizeof(A)); /* print: 1 */ printf("%d\n", sizeof(A1)); /* print: 1 */ printf("%d\n", sizeof(A2)); /* print: 4 */ printf("%d\n", sizeof(B)); /* print: 1 */ printf("%d\n", sizeof(C)); /* print: 4 */ printf("%d\n", sizeof(D)); /* print: 4 */ return 0;}
空类, 及继承空类的类所占空间为1字节, 涉及到虚指针时, 则占4个字节.
参考:
1. 《C++ Primer 中文版》第4版 人民邮电出版社 Page167
2. 《程序员面试宝典(第二版)》电子工业出版社 6.3 sizeof
3. Microsoft Visual Studio 2010 文档
References:
[1] Rationale for International Standard—Programming Languages—C, Revision 2, 20 October 1999. ch6.5.3.4 The sizeof operator
[2] C语言程序:设计现代方法(第2版)(English name, C Programming: A Modern Approach),人民邮电出版社, 吕秀锋,黄倩译. ch7.6 sizeof运算符
- sizeof 操作符
- sizeof 操作符详解
- sizeof 操作符
- sizeof操作符
- 操作符sizeof
- sizeof操作符
- sizeof操作符
- [MSDN]sizeof 操作符
- sizeof 操作符
- sizeof操作符
- sizeof操作符
- 详解sizeof操作符
- 详解sizeof操作符
- sizeof 操作符
- sizeof 操作符详解
- 解读sizeof操作符
- 再论sizeof操作符
- sizeof操作符
- strlen函数的实现
- 动态创建整形数组
- 【转】是该重新定义“人”的时候了
- 指针操作二维数组
- gdb break 断点设置(一)
- sizeof操作符
- JS 的replace
- 银行卡术语
- 添加自己编写的模块到ns-3中出现undefined reference to问题的解决
- redhat linux根目录
- 输出n个不同字符的所有排列方式(据说是京东笔试题)
- 谷歌拼音与魔兽世界
- traceroute一下顺丰快递
- CSS IE6/7/8, Firefox, Safari, Chrome, Opera Hack使用简要归纳