博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
sizeof C++
阅读量:4147 次
发布时间:2019-05-25

本文共 2137 字,大约阅读时间需要 7 分钟。

未完待续

问题1:sizeof是关键字么?

sizeof是数据类型的关键字,而非函数。

引申:预处理指令是否是C语言中的语言类型?

不是。C语言中的语言类型一共有以下5种:

(1)表达式语句

(2)函数调用语句

(3)控制语句

(4)复合语句

(5)空语句

注意:由于预处理指令的结尾不能添加分号,所以预处理指令不是语句

问题2:strlen("\0") = ? sizeof("\0") = ?

strlen("\0") = 0,  sizeof("\0") = 2

  • strlen

执行的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,知道碰到第一个字符串结束符‘\0’为止,然后返回计数器值。

  • sizeof

是C语言的关键字,它以字节的形式给出了其操作数的存储大小,操作数可以是一个表达式或括在括号内的类型名,操作数的存储大小由操作数的类型决定。

两者区别:

  1. sizeof是关键字,而strlen是函数。sizeof后如果是类型必须加括号,如果是变量名可以不加括号。
  2. sizeof的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能够容纳所建立的最大对象的字节大小。
  3. sizeof可以用类型作为参数,strlen只能用char*做参数,而且必须是以‘\0’结尾的。sizeof还可以以函数作为参数,如int g(),则sizeof(g())的值等于sizeof(int)的值,在32位计算机下,该值为4.
  4. 当数组名作为sizeof的参数时不退化。传递给strlen就退化成为指针了。以数组char a[10]为例,在32位机器下,为sizeof(a) = 1*10 = 10,而传递给strlen就不一样了。
  5. 大部分编译程序的sizeof都是在编译的时候计算的,所以可以通过sizeof(x)来定义数组维数,而strlen的计算则是在运行期计算的,用来计算字符串的实际长度,不是类型占内存的大小。例如, char str[20] = "0123456789",字符数组str是编译期大小已经固定的数组,在32位机器下,为1*20 = 20,而其strlen大小则是在运行期确定的,所以其值为字符串的实际长度10.
  6. 当用于计算一个结构类型或变量的sizeof时,返回实际的大小,当用于静态数组时,返回数组的维度,而sizeof不能返回动态数组大小。
  7. 数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。
注意:

在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小,如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy复制出来,长度由另一个形参传进去。

sizeof关心的是编译期为其分配的空间大小不关心里面存了多少数据。

strlen只关心存储的数据内容,不关心空间的大小和类型。

问题3:对于结构体而言,为什么sizeof返回的值一般大于期望值?

  • 一般而言,struct的sizeof是所有成员对其后长度相加,而union的sizeof是取最大的成员长度。
  • 在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照他们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
  • 字节对齐也称为字节填充,它是C++编译器的一个技术手段,主要是为了在空间与复杂度上达到平衡。换句话说,是为了在可接受的空间浪费的前提下,尽可能的提高对相同运算过程的最少(块)处理。
  • 字节对齐的作用不仅是便于CPU的快速访问,使CPU性能达到最佳,同时合理利用字节对齐可以有效的节省存储空间。

在默认情况下,编译器为每一个变量或数据单元按其自然对界条件分配空间。一般地,可以通过下面的方式来改变默认的对界条件:

(1)使用伪指令#pragma pack(n),C编译器将按照n个字节对齐

(2)使用伪指令#pragma pack(n),取消自定义字节对齐方式

(3)_attribute((aligned(n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员长度大于n,则按照最大成员的长度来对齐。_attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

字节对齐的细节和编译器实现相关,但一般而言,满足一下3个准则:

(1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除

(2)结构体每个成员相随与结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节

(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节

需要注意的是:

基本类型是指像char、short、int、float、double等内置数据类型,所谓“数据宽度”就是指其sizeof的大小,32位机器上,这些基本数据类型的sizeof分别是1、2、4、4、8。

问题4:指针进行强制类型转换后与地址进行加法运算,结果是什么?

已不再是指针加法,而变成一个数值加法。

转载地址:http://dfvti.baihongyu.com/

你可能感兴趣的文章
【Python基础8】函数参数
查看>>
【Python基础9】浅谈深浅拷贝及变量赋值
查看>>
Jenkins定制一个具有筛选功能的列表视图
查看>>
【Python基础10】探索模块
查看>>
【Python】将txt文件转换为html
查看>>
[Linux]Shell脚本实现按照模块信息拆分文件内容
查看>>
idea添加gradle模块报错The project is already registered
查看>>
在C++中如何实现模板函数的外部调用
查看>>
在C++中,关键字explicit有什么作用
查看>>
C++中异常的处理方法以及使用了哪些关键字
查看>>
如何定义和实现一个类的成员函数为回调函数
查看>>
内存分配的形式有哪些? C++
查看>>
什么是内存泄露,如何避免内存泄露 C++
查看>>
栈和堆的空间大小 C++
查看>>
什么是缓冲区溢出 C++
查看>>
sizeof C++
查看>>
使用指针有哪些好处? C++
查看>>
引用还是指针?
查看>>
checkio-non unique elements
查看>>
checkio-medium
查看>>