C++ sizeof与strlen,并借此明晰内存对齐
前言
sizeof()与strlen()都是为了获取对象的长度。在正常编写C++的算法程序代码时,可能这两个都很少用到,因为各种stl容器的封装已经给了我们很大的便利,比如我们在想要获取自定义的vector容器里的元素个数,想要获取string类型的字符串的长度时,都只需要调用他们的.size()方法就可以得到容器的长度或者元素的个数。诚然如此,仍会有很多情况需要获取未定义大小方法的对象的大小,比如一个结构体,所以我们还是需要关注这些偏底层的知识,下面就来细细阐述:
sizeof()使用
sizeof() 计算的是变量或类型所占用的内存字节数, 而strlen计算的只能是变量的长度;
#include<iostream>
using namespace std;
struct Node
{
int val1; // 4 bytes
int val2; // 4 bytes
Node* left; // 8bytes
Node* right; // 8 bytes
};
int main(){
cout<<"int:"<<sizeof(int)<<endl; // 4 bytes
cout<<"char:"<<sizeof(char)<<endl; // 1 bytes
cout<<"int*:"<<sizeof(int*)<<endl; // 8 bytes
cout<<"char*:"<<sizeof(char*)<<endl; // 8 bytes
cout<<"Node*:"<<sizeof(Node*)<<endl; // 8 bytes
int x;
cout<<"int x:"<<sizeof(x)<<endl; // 4 bytes
char s[] = "123 456";
cout<<"s[]:"<<sizeof(s)<<endl; // 8 bytes, including '\0'
Node* node = new Node();
cout<<"node:"<<sizeof(*node)<<endl; // 24 bytes, or 8 bytes if sizeof(node), because node is just a pointer.
return 0;
}
总结:
sizeof对于所有的指针,无论指针类型是什么,其所计算的都是指针本身也就是存储的地址值的长度,而对于64位机器,8 bytes足以访问其所有的内存地址(32位机器是4 bytes)。
而对于字符数组类型,会自动计算在其末尾的'\0'运算符,是比strlen()多一个单位的。
对于一个自定义结构体,会自动计算所有成员变量的和。从上可以看出对于两个int类型,两个指针类型他们的字节数分别是4, 4, 8, 8,于是总大小为24bytes。但此时有一个问题,如果把第二个int换为char,答案就是21 bytes了吗?答案是否定的,仍然是24 bytes,这就是内存对齐所导致的结果,sizeof()的值就是对齐之后的值。
关于对齐可以参考:https://zhuanlan.zhihu.com/p/30007037
此处放几个截图可以清晰的说明内存如何对齐(以四字节为对齐标准):
其对齐后的内存布局分别如下:
另外还需注意的是关于最后是否补齐为4或8字节的整数倍还是依具体平台而定。自测如下结构体,只占3字节并未补齐,但是运行x2却发现又补齐了,颇为奇怪:
struct Test{
char c1;
char c2;
char c3;
}test;
更新:经过与朋友讨论,发现是否补齐是依据结构体中最大字节的类型来决定的,平台是MINGW win64,如对于如下结构体:
struct{
long long l1;
char c1;
}x;
上述的x大小为16个字节,c1按照long long的大小去补齐,而不是按照上述所说的有一个统一的内存对齐线。可能这个也会因平台而异吧。
strlen()使用
strlen()是函数,只能去计算以空字符'\0'结尾的字符串,否则是未定义的行为,所以他无法去计算结构体的大小。定义如下:
size_t strlen ( const char * str );
(参数中只能传递字符串类型)
具体使用:
char s[] = "Hello, world!";
strlen(s) // 输出 13,即字符串 s 中有 13 个字符(不包括结尾的空字符 '\0')
区别
那么除了上述用法和结果上的一些区别,即sizeof可以用在任意类型与对象,统计全部的字符大小包括'\0', 而strlen只能统计字符串的长度(不统计'\0').在底层实现时也有一些区别:
sizeof()是运算符,strlen()是库函数
sizeof()在编译时计算好了,strlen()在运行时计算
sizeof()计算出对象使用的最大字节数,strlen()计算字符串的实际长度
sizeof()的参数类型多样化(数组,指针,对象,函数都可以),strlen()的参数必须是字符型指针(传入数组时自动退化为指针)
其实两者之前共同点就只在于都可以计算字符数组的长度,其他尽不相同。
C++ sizeof与strlen,并借此明晰内存对齐的更多相关文章
- c/c++中关于sizeof、strlen的使用说明
sizeof: 一般指类型.变量等占用的内存大小(由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小) strlen: c字符串的长度(参数必须是字符型指针 char*,当数组名作 ...
- sizeof、strlen、字符串、数组,整到一块,你还清楚吗?
写在前面 sizeof.strlen.字符串.数组,提到这些概念,相信学过C语言的人都能耳熟能详,也能谈得头头是道,但是,在实际运用中,当这些内容交织在一起时,大家却不一定能搞地清清楚楚,本文的目的正 ...
- sizeof和strlen的区别
一.sizeof sizeof(...)是运算符,而不是一个函数. sizeof操作符的结果类型是size_t,在头文件中typedef为unsigned int,其值在编译时即计算好了, ...
- Sizeof与Strlen的区别与联系
转自:http://www.cnblogs.com/carekee/articles/1630789.html 一.sizeof sizeof(...)是运算符,在头文件中typedef为uns ...
- Sizeof与Strlen的区别与联系(转)
Sizeof与Strlen的区别与联系 一.sizeof sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组.指针.类型 ...
- sizeof()和strlen()
sizeof计算的是栈中大小 P { margin-bottom: 0.21cm; direction: ltr; color: rgb(0, 0, 0); text-align: justify } ...
- sizeof 和 strlen 的区别
sizeof 和 strlen 都是c/c++ 中常见的符号,他们的功能是判断数组长度.那么他么到底有什么区别 1.sizeof 不是函数,而是一个操作符.字节数的计算在程序编译时进行,而不是在 ...
- C++-sizeof和strlen的区别
一.sizeof sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组.指针.类型.对象.函数等. 它的功能是:获得保 ...
- sizeof 和 strlen 区别
Sizeof与Strlen的区别与联系 一.sizeof sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组.指针.类型. ...
- sizeof()与strlen()的区别
首先需要说明的是sizeof和strlen都可以求长度,但是却有很大的区别,简单来说可以概括为以下几点: 1.sizeof是一个关键字,而strlen确实一个函数. 2.sizeof求的是字节长度,而 ...
随机推荐
- JMeter参数化(一)--CSV参数化
一.CSV Data Set Config 1.添加配置元件-CSV Data Set Config 其中,分隔符不能是参数化的值中的符号,否则会被截断. 2.调用 3.循环读取文件中数据 假设数据内 ...
- Tutorial_WorkflowProcessor usage in AX 2012
Check under system administration if the BC proxy and workflow excecution account are still valid. C ...
- junit单元测试踩过的坑
1.测试方法不能直接获取到系统初始化的配置信息,需要专门读取 2.单元测试多线程子线程不执行,不会像主线程一样等待子线程退出而退出, 会直接退出. . https://blog.csdn.net/yu ...
- Apache Ranger系列七:Hive 和 Spark 执行过程中的文件路径配置
背景:在使用Ranger鉴权的过程中,要求必须开启impersonation功能(即执行用户与提交用户保持一致,而不是统一代理的hive/spark).但是在执行的过程中,会需要在hdfs存储临时的文 ...
- selenium 模拟鼠标滚轮,滚动到可见的选项
self.wrap_driver.move_to_element(locator=const_xpath.monitor_select) #鼠标移动到某个区域target = self.driver. ...
- LeetCode86 分隔链表
idea: 烦死了,这个题一直因为创立的指针为空,或者接入结点方法不对,结果将两个小链表搞混乱了,不过具体思路ok.将小值结点成一组,大值结点成一组,最后在首尾相连,实现起来也比较简单 /** * ...
- 还不知道如何在java中终止一个线程?快来,一文给你揭秘
目录 简介 Thread.stop被禁用之谜 怎么才能安全? 捕获异常之后的处理 总结 简介 工作中我们经常会用到线程,一般情况下我们让线程执行就完事了,那么你们有没有想过如何去终止一个正在运行的线程 ...
- windows微信如何双开
生活中存在同时使用两个微信的情况,一个工作一个生活,这时希望同时在电脑上登录两个账号.如何做到呢?步骤如下: 右键单击"微信"图标,选择属性,目标框内的路径就是微信安装路径,复制目 ...
- SpringBoot解决跨域方案
SpringBoot解决跨域的几种方式 跨域资源共享(CORS):通过修改Http协议header的方式,实现跨域.说的简单点就是,通过设置HTTP的响应头信息,告知浏览器哪些情况在不符合同源策略的条 ...
- salesforce零基础学习(一百二十七)Custom Metadata Type 篇二
本篇参考: salesforce零基础学习(一百一十一)custom metadata type数据获取方式更新 https://developer.salesforce.com/docs/atlas ...

