您的位置:首页 > 编程语言 > C语言/C++

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

2016-02-25 16:05 525 查看
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)的问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: