C/C++基础::sizeof() 与 sizeof(string)

来源:互联网 发布:c语言产生0 9的随机数 编辑:程序博客网 时间:2024/05/01 13:53

sizeof(string 对象) ≠ string 对象的.size()成员函数(.size()与.length()不作区别,返回 string 的字符个数)

string 的实现在各库中可能有所不同,但在同一个库中相同的一点是,无论string里存放了多长的字符串,它们的sizeof()都是固定的(举个不太恰当的例子,就好比,int a; 无论int变量a取多大的值,sizeof(a)总为4),字符串所占的空间是从堆中动态分配的,与sizeof()无关;

sizeof(string) == 4可能是最为典型的实现之一,不过也有sizeof()为 12,32 字节的库,同时也与编译器有关,在windows 32位操作系统下, 使用vs2013编译器测试,sizeof(string) == 28

char buf[] = "hello";                // buf真正指向的是"hello\0",\0也独占一个字节std::cout << sizeof(buf) << std::endl;                // 实际所占的内存空间的大小,5+1(\0)=6std::cout << strlen(buf) << std::endl;                // strlen 的头文件在 <string.h>                // <string> 也有其实现                // 该函数遇 `\0` 结束std::string str = buf;                // 支持参数为char*的单参构造std::cout << buf.size() << std::endl;                // == 5,不将`\0`计算在内                // 等价于 buf.length()std::cout << sizeof(std::string) << std::endl;                // == 28,库及编译器的缘故std::cout << sizeof(buf) << std::endl;                // 与字符串自身的长度无关

sizeof()、strlen() 与 \0 的关系

char buf[] = "he\0llo";std::cout << sizeof(buf) << std::endl;                                              // 实际所占内存空间的大小,与`\0`的位置无关,                        // 但会在字符串的末尾自动加上`\0`,也即 he\0llo\0std::cout << strlen(buf) << std::endl;                                              // 遇第一个\0结束统计

也即:

  • sizeof():对象在内存中所占空间的真实大小

  • strlen():遇第一个\0结束大小的统计,也即不视\0后的字符为当前字符串的内容,事实上,也确实如此;

std::cout << buf << std::endl;                    // he                    // 字符串的赋值以`\0`为结束

sizeof 何人?

msdn 给出如下的定义:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

return 让我们联想,sizeof() 是否是一个函数?答案是否定的,sizeof(object) 可以执行,sizeof object也是可以执行的(但仅限于变量或者对象,类型不支持该操作,也即sizeof int,就会报错,()是永远正确的操作),显然不满足于C语言对函数的要求。有人说 sizeof 是一元操作符,事实也并非如此,sizeof 更像是一个特殊的宏,在编译阶段求值;

cout << sizeof (int) << endl;                // 32位机,int 占4个字节cout << sizeof (1==2) << endl;                // sizeof(bool)

在编译阶段已被翻译为:

cout << 4 << endl;cout << 1 << endl;

这里有一个著名的陷阱:

int a = 1;cout << sizeof(a = 3) << endl;cout << a << endl;

输出不是预期的4,3而是4,1,可见 a 的初始值并未被改变,也即a=3并未被真正执行。原因正在于,sizeof()的编译阶段处理的特性了。由于sizeof不能被翻译成机器码,所以sizeof的作用范围内,也就是()里面的表达式(expression)不能被编译,而是被替换为类型,赋值操作符(=)返回左操作数的类型,所以 a=3在sizeof()看来就相当于int,而代码也被替换为:

int a = 1;cout << 4 << std::endl;cout << a << std::endl;

所以,结论就是:

不可在sizeof作用于一个表达式(sizeof(++a)),在sizeof()看来,该表达式最后等效于一个类型,表达式不会被编译,更不会被执行;

sizeof 操作函数类型

int f1(){return 0;};double f2(){return 0.0;}void f3(){}cout<<sizeof(f1())<<endl; // f1()返回值为int,因此被认为是intcout<<sizeof(f2())<<endl; // f2()返回值为double,因此被认为是doublecout<<sizeof(f3())<<endl; // 错误!无法对void类型使用sizeofcout<<sizeof(f1)<<endl;   // 错误!无法对函数指针使用sizeof   cout<<sizeof*f2<<endl;   // *f2,和f2()等价,                         //因为可以看作object,所以括号不是必要的。被认为是double

结论:对函数使用sizeof,在编译阶段会被函数返回值的类型取代,同样,虽然调用的动作,函数并不会被真正执行;

int foo(){    std::cout << "foo()" << std::endl;}int main(int, char**){    std::cout << sizeof(foo()) << std::endl;                        // 只输出为 4                        // "foo()":不会被输出    return 0;}

References

[1] sizeof和sizeof(string)的问题

0 0