vs2019测试sizeof(string)的长度是28

2023-05-16

在csdn回答别人的问题时,偶然间接触到sizeof求sting的内存容量大小的问题,经过测试,结果有些意外,引发自己的深度思考,探索一番做整理。

0:相关知识点

为了分析sizeof(string)的大小,涉及到一些知识点:

====》sizeof()是静态运算符,关注的是参数类型,编译时决定了。

====》类的长度实际是类中非静态成员变量长度,无成员变量是1,有虚函数要维持虚函数表(一个指针大小),有基类时要算基类的成员吧。

====》类模板(通用的类)和模板类(实例化的类)的概念

====》可以用using对复杂的结构重新命名。

====》string的内存分配,实际上还是类中定义一个指针,真正赋值的时候去new具体的大小。

====》typename的新用法:用在模板定义中,把相关名称识别为类型。

1. 问题描述(单纯记录引发我思考的起点):

有新手同学在使用string及数组的时候,有误用,引发我的思考:

//他的本意应该是想定义时确定一个数组的大小,故这样写了代码
string s;
char c[strlen(s.c_str())]={0}; //都是不对的代码
int a[strlen(s.c_str())]={0};

我能明确看出他的不对,因此我期望用demo去给他验证,数组下标是0,这里就涉及字符串string的一个长度问题,我抛出:

//这是在vs 2019上运行的结果:
int main()
{
	string s;
    //这里我的本意是让他理解及去梳理strlen(),length(),以及sizeof()这几个求长度函数的差异,却让自己深思一下
	cout << strlen(s.c_str()) << endl;    //0
	cout << s.length() << endl;           //0
	cout << sizeof(s) << endl;            //28
	cout << sizeof(string) << endl;       //28
	return 0;
}
//探索后,发现在linux上运行的结果
#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
	string s;
	cout << strlen(s.c_str()) << endl;    //0
	cout << s.length() << endl;           //0
	cout << sizeof(s) << endl;            //32
	cout << sizeof(string) << endl;       //32
	return 0;
}

检测测试发现:

VS2019上sizeof(string)的长度是28

linux上sizeof(string)的长度是32

VS2022上sizeof(string)的长度是40

2. 为什么sizeof(string)的长度是28,以及32,40

第一眼懵逼,问了一把身边同事,他随口回答是类似array的预分配内存

===>emmmm,有点涉及,但是依然不对,这是string的其他知识点

结合百度,明确以下信息:

====》用sizeof求string的结果,在不同的系统中结果是不同的。

====》用sizeof求string的大小,与string是否初始化也是无关的。

====》sizeof是静态运算符,在编译的时候获取到响应结果,而string对象的申请,一般都是在运行时动态分配。

反思到,sizeof所求,其实是类所占用的大小,可以跟踪代码进行探索。

3:跟踪一下string类的大小

这里我在vs2019上试图跟踪了一下string类。 其他的类似吧~

//string实际是 类模板 传入char
using string  = basic_string<char, char_traits<char>, allocator<char>>;

//第一步:
//这里实际是关注basic_string 中传入char时类所占内存的大小。
//实际测试:
cout << sizeof(basic_string111<char, char_traits<char>, allocator<char>>) << endl;   //28
//简化basic_string 相关的类中成员,最终类简化后占用内存的成员是:
template <class _Elem, class _Traits = char_traits<_Elem>, class _Alloc = allocator<_Elem>>
class basic_string111 { // null-terminated transparent array of elements
private:
	using _Alty = _Rebind_alloc_t<_Alloc, _Elem>;
	using _Alty_traits = allocator_traits<_Alty>;
	using _Scary_val = _String_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Elem>,
		_String_iter_types<_Elem, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
		typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;
private:
	_Compressed_pair<_Alty, _Scary_val> _Mypair;  //这是实际占用的
};

//第二步:
//这里就需要研究成员变量的的大小了:    _Compressed_pair<_Alty, _Scary_val> _Mypair;
//实际测试:
cout << sizeof(_Alty) << endl;        //1
cout << sizeof(_Scary_val) << endl;   //28
cout << sizeof(_Compressed_pair<_Alty, _Scary_val>) << endl;     //28

//第三步
//接下来需要研究成员大小:    _Compressed_pair<_Alty, _Scary_val>大小为什么是28
//首先获取到 _Compressed_pair 实际也是一个类模板    中间有个成员变量 实际是模板第二个参数
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
public:
    _Ty2 _Myval2;
    using _Mybase = _Ty1; // for visualization
};

//====>所以 _Compressed_pair 的大小,实际上可以确定是第二个模板参数 也就是_Scary_val 的大小。
//====>_Scary_val  实际又是 类模板 
using _Scary_val = _String_val<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<_Elem>,
		_String_iter_types<_Elem, typename _Alty_traits::size_type, typename _Alty_traits::difference_type,
		typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Elem&, const _Elem&>>>;
// ====》也就是确定 这个类模板 对应传参实际大小   
template <class _Val_types>
class _String_val111 : public _Container_base {
public:
	// length of internal buffer, [1, 16]:
	static constexpr size_type _BUF_SIZE = 16 / sizeof(char) < 1 ? 1 : 16 / sizeof(char);  

	union _Bxty { // storage for small buffer or pointer to larger one
		_Bxty() noexcept {} // user-provided, for fancy pointers

		~_Bxty() noexcept {} // user-provided, for fancy pointers

		value_type _Buf[_BUF_SIZE];
		pointer _Ptr;
		char _Alias[_BUF_SIZE]; // TRANSITION, ABI: _Alias is preserved for binary compatibility (especially /clr)
	} _Bx;

	typename size_t _Mysize; 				// 4个字节 typedef unsigned int     size_t;
	typename _Val_types::size_type _Myres;  // 4个字节 实际是模板参数传参对应的size_type 类型  实际还是size_t
};

//第四步:实际上就是分析_String_val111 所占大小
//为了确定_Val_types::size_type 的类型及长度    跟踪一下模板参数:conditional_t 
_String_val111<conditional_t<_Is_simple_alloc_v<_Alty>, _Simple_types<char>,
		_String_iter_types<char, typename _Alty_traits::size_type, typename _Alty_traits::difference_type, typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, char&, const char&>>>
//可以确定他实际是  _Simple_types<char>中对应的size_type    
 template <class _Value_type>
struct _Simple_types1 { 
	using value_type = _Value_type;
	using size_type = size_t;   //===》实际是这个  也是unsigned int
	using difference_type = ptrdiff_t;
	using pointer = value_type*;
	using const_pointer = const value_type*;
};
//分析后可以确定   
//_String_val111 类中,成员变量的长度是 union (16) + size_t(4) +_Val_types::size_type(4)  +基类成员中有一个指针(4) = 28

最终 跟踪vs2019中string相关类的定义,可以确定sizeof(string)所求长度就是类中成员变量的总长度 28

4:总结涉及到的知识点。

为了分析sizeof(string)的大小,涉及到一些知识点:

====》sizeof()是静态运算符,关注的是参数类型,编译时决定了。

====》类的长度实际是类中非静态成员变量长度,无成员变量是1,有虚函数要维持虚函数表(一个指针大小),有基类时要算基类的成员吧。

====》类模板(通用的类)和模板类(实例化的类)的概念

====》可以用using对复杂的结构重新命名。

====》string的内存分配,实际上还是类中定义一个指针,真正赋值的时候去new具体的大小。

====》typename的新用法:用在模板定义中,把相关名称识别为类型。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vs2019测试sizeof(string)的长度是28 的相关文章

  • 将 h1 元素的内容复制到剪贴板?

    所以 我做了一个翻译器 但效果不是很好 但无论如何 它正在工作 我想尝试添加一些可以复制结果的内容 有没有办法做到这一点 以下是我的代码 提前致谢 我知道有一种方法可以通过输入来完成此操作 但我不确定是否可以通过标题来完成 var myTe
  • string.Equals (c#) 的区域性参数何时真正产生影响的示例?

    我不完全理解 string Equals 的第二个参数 这是因为我找不到任何例子来说明它何时会真正产生影响 例如 无论第二个参数的值如何 除了 IgnoreCase 这里给出的示例都是相同的 http msdn microsoft com
  • perl生成字符串来匹配正则表达式

    我尝试找到一种方法来生成与正则表达式匹配的字符串 例如以下正则表达式 A Z 6 6 A Z2 9 A NP Z0 9 A Z0 9 3 3 0 1 我尝试过 Cpan 上的一些 perl 模块不起作用 gt 字符串 随机 gt 正则表达式
  • 字符串数组初始化

    这是另一个的延续question https stackoverflow com questions 7834294 string array conversion I have 考虑以下代码 char hi hello char arra
  • 从 Kotlin 中的字符串中删除字符

    我正在尝试创建一个使用 Kotlin 中的字符串的 Android 计算器 如果逗号 或负数 已经包含一个 我不知道如何删除它 这是我的代码 它正确添加逗号 但如果用户再次单击则不会删除它 if buClickValue contains
  • Java中的String为什么是不可变的对象,但我在创建一个对象后仍然可以更改它的值? [复制]

    这个问题在这里已经有答案了 如果我可以创建一个字符串并给它一个值 这怎么可能呢 然后 我可以像这样简单地覆盖它的值 String a abc a def 我怎么可能改变的值a 我一定在这里遗漏了一些东西 我知道每当创建 String 对象时
  • 使用 Hibernate 映射 Map

    似乎在我看来 到处都有过时的版本 不再起作用 我的问题看起来很简单 我有一个 Java 类 它映射到 derby 数据库 我正在使用注释 并成功地在数据库中创建了所有其他表 但在这个特定的示例中 我只需要一个 Map 它不使用任何其他类 只
  • C# 中将一个字符串拆分为另一个字符串

    我一直在使用Split 分割字符串的方法 但这似乎仅在您按字符分割字符串时才有效 有没有办法分割一个string 另一个字符串是按参数分割的 我尝试将拆分器转换为字符数组 但没有成功 换句话说 我想分割string THExxQUICKxx
  • python中打印字符串的长度

    有没有什么方法可以找到 即使是最好的猜测 Python中字符串的 打印 长度 例如 potaa bto 是 8 个字符len但 tty 上只打印 6 个字符宽 预期用途 s potato x1b 01 32mpotato x1b 0 0mp
  • 从 Perl 中的字符串中删除标点符号

    如何从 Perl 中的字符串中删除除空格之外的所有标点符号 s punct g
  • django如何将字符串转换为模块?

    我试图了解 django 的另一个神奇之处 它可以将字符串转换为模块 In settings py INSTALLED APPS声明如下 INSTALLED APPS django contrib auth django contrib c
  • Python Pandas:如何替换包含“?”的字符串

    我有一个 Python 2 7 Pandas Dataframe 如下所示 Id Title URL Id 1 Bruce Almighty https www youtube com watch v 5VGyTOGxyVA Id 2 Su
  • 在 Java/Android 中检查字符串是否包含 URL 的最佳方法是什么?

    在 Java Android 中检查字符串是否包含 URL 的最佳方法是什么 最好的方法是检查字符串是否包含 com net org info 其他 或者有更好的方法吗 url 输入到 Android 中的 EditText 中 它可以是粘
  • 如何将动态格式字符串与格式一起使用!宏?

    我想使用format 宏与String作为第一个参数 但因为宏需要字符串文字 所以我无法传递任何与它不同的内容 我想这样做是为了将字符串动态添加到当前字符串中 以便在视图引擎中使用 如果有更好的方法 我愿意接受建议 let test Str
  • 什么定义了类型的大小?

    ISO C 标准规定 sizeof char lt sizeof short lt sizeof int lt sizeof long 我在 BIT Linux mint 19 1 上使用 GCC 8 大小为long int is 8 我正
  • 如何释放字符串未使用的容量

    我正在程序中处理很多字符串 这些字符串数据在读入我的程序后的整个生命周期内都不会改变 但由于 C 字符串保留了容量 因此浪费了大量肯定不会被使用的空间 我尝试释放这些空间 但没有成功 以下是我尝试过的简单代码 string temp 123
  • 忽略Python字符串中的大小写[重复]

    这个问题在这里已经有答案了 在Python中比较字符串 忽略大小写 的最简单方法是什么 当然可以这样做 str1 lower 我想我正在寻找与 C 的 stricmp 等效的函数 需要更多上下文 所以我将用一个简单的例子来演示 假设您要对一
  • 如何在 Swift 中证明 String 类型的“写时复制”

    正如标题所说 我试图证明自己 Swift 中的 String 支持 COW copy on write 但我找不到证据 在尝试以下代码后 我在数组和字典上证明了 COW func address of object UnsafeRawPoi
  • 如何反转字符串中的单词但将标点符号保留在正确的位置? [复制]

    这个问题在这里已经有答案了 我编写了以下代码来反转输入字符串 Scanner s new Scanner System in System out println Please enter a sentence String sentenc
  • PHP 中的多行字符串文字

    考虑 xml l xml vv echo xml 这将回响vv 为什么以及如何为诸如此类的事情执行多行字符串文字简单XML https en wikipedia org wiki SimpleXML etc Well xml l vv Wo

随机推荐