c++ - 内存中的字符数组表示
问题描述
我试图对 char 数组执行按位运算,就好像它是一个 int 一样,本质上将字节视为内存中的一个连续区域。下面的代码说明了我的问题。
char *cstr = new char[5];
std::strcpy(cstr, "abcd");
int *p = (int *)(void *)cstr;
std::cout << *p << " " << p << "\n";
std::cout << cstr << " " << (void *)cstr << "\n";
std::cout << sizeof(*p) << "\n";
(*p)++;
std::cout << *p << " " << p << "\n";
std::cout << cstr << " " << (void *)cstr << "\n";
产生以下输出:
1684234849 0x55f046e7de70
abcd 0x55f046e7de70
4
1684234850 0x55f046e7de70
bbcd 0x55f046e7de70
快速解释代码及其工作原理(据我了解):
我用“abcd”初始化 cstr
char *cstr = new char[5];
std::strcpy(cstr, "abcd");
我将 p 指向 cstr 的地址并指定我希望它是一个 int
int *p = (int *)(void *)cstr;
我测试 p 指向它应该指向的位置并且它占用 4 个字节
std::cout << *p << " " << p << "\n";
std::cout << cstr << " " << (void *)cstr << "\n";
std::cout << sizeof(*p) << "\n";
然后我增加地址 p 指向的整数
(*p)++;
所以现在,由于“abcd”是内存中一个连续的 32 位块,加 1 应该会产生“abce”。相反,代码成功地递增整数,但将 char 数组保留为“bbce”。最后一部分检查整数和 cstr 的新值
std::cout << *p << " " << p << "\n";
std::cout << cstr << " " << (void *)cstr << "\n"
这是预期的行为吗?
PS:我在一台linux机器上使用这个命令编译了代码:g++ main.cpp -o main。
file main
产生以下输出:“1:ELF 64 位 LSB 共享对象,x86-64,版本 1 (SYSV),动态链接,解释器 /lib64/ld-linux-x86-64.so.2,用于 GNU/Linux 3.2 .0"
解决方案
x86-64 CPU(如您的)将多字节整数的最低有效字节存储在最低内存地址。因此,递增“abcd”对应的整数会导致递增其最低有效字节,该字节首先存储在内存中。这将“a”字符转换为“b”。此类代码的行为方式在很大程度上取决于 CPU 如何对整数和字符串进行编码,以及您对这段代码将要做什么的期望必须考虑这些细节。
要期待字符串“abce”,您必须做出很多假设:
- 您必须期望整数占用 4 个字节。
- 您必须期望最后存储最低有效字节。
- 您必须期望字符“e”的编码比字符“d”的编码多一。
- 当被视为有符号整数增量时,您必须期望将“d”递增到“e”不会溢出。
其中一些是合理的假设,而另一些则不是,但是除非您对所有这些假设都有合理的理由,否则您的期望是不合理的。
这是预期的行为吗?
这是熟悉您的平台的人所期望的。但通常很容易避免依赖这些假设,因此最好的建议是不要依赖它们。假设 3 在所有现代平台上通常是不可避免且合理的。
推荐阅读
- kaggle - 如何在无需注册的情况下快速从 Kaggle notebook 获取代码?
- php - PUT 不更新实体
- php - 以编程方式发送 Ninja Forms 通知
- mysql - mysqli 查询带有编码的多个案例
- c# - 如何禁用恢复 Visual Studio 安装程序项目的丢失文件?
- php - 替换数组键并用它们移动值
- mysql - 如何仅对具有正支付总额的记录进行分组?
- json - 如何正确将 JSON 导入 Excel
- kubernetes - Kubernetes - 在容器之间共享单个文件(在同一个 pod 内)
- powerbi - 计算 RELADTABLE 的 MAX