各种数据类型的变量如何存储在C++(本机)二进制文件中
How are variables of various data types stored in C++(native) binary?
一周前,我和C++一起开始了我的冒险。我读了很多关于C++。我正在尝试以下内容:
char * String1 = "abcdefgh";
然后,我尝试通过以下方式修改其值:
String1[2] = 'f';
这导致了未处理的异常。但以下结果会导致正确执行:
char String2[9]="abcdefgh";
String2[7]='s';
我尝试使用 DUMPBIN 提取有关使用上述代码生成的二进制文件的信息。DUMPBIN是一个Visual Studio工具。我使用/ALL 选项提取二进制文件中包含的所有信息。
我可以在 RAWDATA 部分看到两个"abcdefgh"实例。我明白为什么。
我的问题如下:
1) 虽然 String1 和 String2 本质上都是指向同一字符序列的两个不同实例的指针,但为什么 String1 操作不是合法的?
2)我知道编译器会生成一个符号表来映射变量名称及其值。有没有工具可以在Windows操作系统中可视化符号表?
3)如果我有一个整数数组而不是字符序列,可以在RAWDATA中找到它吗?
我还可以在 RAWDATA 中看到以下内容:
Unknown Runtime Check Error.........
Stack memory around _alloca was corrupted.......
....A local variable was used before it was initialized.........
....Stack memory was corrupted..
........A cast to a smaller data type has caused a loss of data.
If this was intentional, you should mask the source of the cast with the appropriate bitmask.
这些东西是如何进入二进制可执行文件的?将这些消息放在二进制文件中的目的是什么(显然是不可读的)?
编辑:我的问题 1) 有一个词 实例,用于表示以下内容:
字符序列"abcdefgh"派生自一组非大写的英文字母,即{a,b,...,y,z}。这个序列被实例化两次,并存储在两个内存位置,比如A和B.String1指向A(假设),String2指向B。这个问题中没有概念上的混淆。
我想理解的是内存位置 A 和 B 的属性差异,即为什么其中一个是不可变的。
注意:下面的所有代码都引用了函数中的一个作用域。
下面的代码初始化一个可写缓冲区string2
数据。编译器生成初始化代码,以从只读编译器生成的字符串复制到此缓冲区。
char string2[] = "abcdefgh";
下面的代码在 string1
中存储指向编译器生成的只读字符串的指针。字符串的内容位于可执行映像的只读部分中。这就是为什么修改它会失败的原因。
char * string1 = "abcdefgh";
可以通过string1
指向可写缓冲区来使其工作。这可以通过复制字符串来实现:
char * string1 = strdup("abcdefgh");
....
free(string1); // don't forget to free the buffer!
char * String1 = "abcdefgh";
在 C(和 C++)中是 const,编译器可以随心所欲地存储固定的 const 数据,它可能有一个单独的 DATA 段,它可能具有完全的 const 程序存储(在哈佛架构中)
char String2[9]="abcdefgh";
分配一个 9 个元素的字符数组,恰好用一些字符串初始化它。您可以对阵列执行所需的操作。任何其他类型的数组都将以相同的方式存储。
某些运行时错误的错误消息存储在程序数据段中(与原始 char* 字符串相同)。其中一些像"这个程序需要Windows"显然必须在那里而不是在操作系统中,因为DOS不知道一个程序需要更高版本的Windows。 但我不确定为什么这些特定的运行时错误不是由 OS
不能修改字符串文本。 字符串文本的类型为 char const[]
,任何修改一个的尝试都是未定义的行为。并给出如下声明:
char* s1 = "a litteral";
,编译器确实应该生成警告。 隐含的此处不推荐转换为非 CONST,并且仅引入到避免破坏现有代码的语言(从某个时代开始C 没有const
)。
在这种情况下:
char s2[] = "init";
,实际上没有字符串文字。 "字符串文字"实际上是一个初始化规范与字符串文本不同,不会出现内存中的任何位置;编译器使用它来确定如何s2
应该初始化,并且完全等效于:
char s2[] = { 'i', 'n', 'i', 't', ' ' };
(写起来更方便一些。
--简短的历史侧面:早期的C没有const
. 的类型字符串文字是char[]
的,修改它是合法的。 这个线索到一些非常可怕的代码:
char* f() { return "abcd"; }
/* ... */
f()[1] = 'x';
下次你打电话给f
,它返回"axcd"
。 一窝没有源列表中显示的值是不是可读代码的方式,C 标准委员会决定这是一个最好不要保留的功能。
char string[] = "foo"
这将分配一个 char 数组,并使用值 {'f', 'o', 'o', '\0'} 初始化它。您可以获得字符的"自己的"存储,并且可以修改数组。
char strptr* = "foo"
这将分配一个指针,并将该指针的值设置为包含 {'f', 'o', 'o', '\0'} 的 char 数组的地址。指针是你随心所欲的,但 char 数组不是。事实上,数组的类型不是char[]
,而是const char[]
,strptr
确实应该声明为 const char*
,这样你就不会错误地尝试修改 const 数组。
在第一种情况下,"foo"
是数组初始值设定项。在第二个中,"foo"
是字符串文本。
关于每种情况下的内存确切位置的更具体细节往往未由标准指定。但是,一般来说,char string[] = "foo"
在堆栈上分配一个char
数组,char strptr* = "foo"
堆栈上分配一个char
指针,并(静态地)在可执行文件的数据部分中分配一个const char
数组。
如 c++ 标准 (2003) (http://www.iso.org/iso/catalogue_detail.htm?csnumber=38110) 中所指出的
1 字符串文本是用
双引号,可选以字母 L 开头,如"..." 或 L"..."。 不以 L 开头的字符串文本是一个 普通字符串文本,也称为窄字符串 字面。 普通字符串文本的类型为"n 个常量
数组" char"和静态存储持续时间 (basic.stc),其中 n 是大小 的字符串如下定义,并使用给定的 字符。 以 L 开头的字符串文本(如 L"asdf")是 宽字符串文本。 宽字符串文本的类型为"n 的数组" const wchar_t",并具有静态存储持续时间,其中 n 的大小为 下面定义的字符串,并使用给定的字符初始化- 之三。2 是否所有字符串文本都是不同的(即存储 在非重叠对象中)是实现定义的。 这 尝试修改字符串文本的效果未定义。
如上所述,这不是非法的,是未定义的行为,因此,使用 VS,您会在 Windows 上出现异常,使用 g++,您将在 Linux 中出现分段错误(基本上它们看起来很相似)
2)您可以使用反汇编程序并检查exe文件的数据部分(查看此wiki以获取有关几个exe文件结构x86反汇编/Windows可执行文件的更多信息)
3)是的,它应该在exe文件的.data部分
- 从C++本机插件更新Vector3数组
- GCC本机矩阵运算库
- VC++本机单元测试,找不到调试符号
- 在这种情况下,java对象是否可以调用本机函数
- PC中的程序和PHONE中的本机描述应用程序之间的数据连接
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 无法将标准库导入本机 android 项目中的头文件
- 使用本机 C++ 应用程序中的 C# 代码
- 在nodejs中使用本机代码的最佳方法是什么?
- 如何告诉本机节点模块所需的dll存储在哪里?
- 在自定义程序中使用本机 Windows 自然顺序排序
- 如何在C++非托管/本机 DLL 中从注册免费 COM C# 托管 DLL 创建 COM 对象
- MS 本机单元测试 - 断言::线程失败不起作用
- 将音频从浏览器流式传输到WebRTC本机C++应用程序
- Winapi - SetWindowLongPtr in ShutdownBlockReason创建/销毁JNI本机代码
- C++/CLI 混合托管/本机 DLL 不起作用
- 子系统中的异常处理:本机
- 多次调用本机方法时出现致命错误
- 如何使用 Malloc 调试来检查本机内存泄漏?
- 使用本机 JNI 静态方法实现C++ Java 运行时错误