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

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)=6
std::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\0
std::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,因此被认为是int

cout<<sizeof(f2())<<endl; // f2()返回值为double,因此被认为是double

cout<<sizeof(f3())<<endl; // 错误!无法对void类型使用sizeof

cout<<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)的问题

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值