sizeof是编译时的一元操作符, 返回任意对象所属类型的大小(单位:字节). 值的类型是size_t, 表示无符号整数, 它是个宏, 可以定义为unsigned int或unsigned long.
形式如下:
sizeof(type name);
sizeof(expr);
sizeof expr;
sizeof中的圆括号不是必须的, 但是一元操作符的优先级高于二元操作符, 表达式sizeof a + b会被编译器误认为sizeof(a) + b. 所以圆括号有时候是必须的.
它的值在编译时确定.
例外情况是: 如果操作数是可变长度的数组类型(c99)
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]
C标准要求sizeof(char)的值一定是1, 其他类型根据具体实现而定.
除了位域、函数名和空表达式, 其他任何值都可以[1](待测试...fix me!).
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函数代替strcpy函数, 防止数组溢出. 假设有字符数组a和b, 现在要将字串b复制到a中, 由于不知道b的长度, 又要保证a不溢出, 所以惯用的方法如下:
strncpy(a, b, sizeof(a) - 1);
a[sizeof(a) - 1] = '\0';
有人写了以下两个函数, 分别用来获取数组所占用的字节数和复制字符数组:
#include
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!见谅, 以下内容待修改.
在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运算符