IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【编译汇编链接】全局变量 char* g_str 和 char g_str[] -> 正文阅读

[C++知识库]【编译汇编链接】全局变量 char* g_str 和 char g_str[]

请在Debug模式下进行文章涉及的操作,以避免Release行为优化了部分细节。

一、产生

针对如下代码,先提出一个问题,g_strg_str1有何异同?LINE 1LINE 2执行情况如何?

// 代码`1-1`
#include <iostream>
char g_str[] = "hello";
char *g_str1 = (char*)"world";
int main()
{
	g_str[0] = '1'; // LINE 1
	g_str1[0] = '1'; // LINE 2
}

二、分析

先回答一下提出的第一个问题:

首先g_strg_str1都是全局变量,并且都存储在静态存储区。并且可以确定的是,两者都有自己的地址段。
调试截图

但是两者在本质上是有区别的。

  1. 在声明上,g_str是一个长度为6char类型的数组,g_str1是一个char类型的指针。

首先,如果仅仅是执行read操作的话,两者是都可以正常执行的,比如下边这两行代码

// 代码`2-1`
 pritnf("%s",g_str);
 printf("%s",g_str1);

但是如果你尝试对两者进行修改操作时,结果会怎样?也就是代码1-1中的操作。依次执行,修改g_str[0]正常执行,修改g_str1[0]则会报错写入访问权限冲突,报错情况如下所示:
报错情况——写入访问权限冲突
这个问题解释起来很简单,由于汇编过程中将不同的代码放入了不同的地方,而这些地方的权限也不尽相同,以上操作导致了一个不可被write的数据发生了write行为,所以编译器报错了。这也就引出了第二个不同点。
?
但是,上述问题在Release模式下就不会产生。有待研究

  1. 访问权限不同,一个是常量全局变量,一个是非常量全局变量

可以看到在声明g_str1的时候进行了强制转换的操作,不强制转换的话,编译器会报错,告诉你不能把一个const char *的用来初始化一个char*的实体。
?

这里往往最容易被忽略的一点就是char *g_Str1 = (char*)"world";这行代码中的"world",其实是一个const char *。也就是你在声明并定义g_Str1的时候,其实是把一个const区域的指针强转给了g_str1。因此在修改g_str[0]的时候会出现访问权限拒绝,因为g_str1本身就只指向了一个cosnt的内存段。

三、结合编译文件查看一下上述问题产生的原因

使用Dumpbin工具查看一下代码2-1的.obj文件

从这里开始所提到的段落都是.obj文件中的SECTION HEADER,如SECTION HEADER #5即指段落5。

  1. 首先看一下符号表中的相关项:
    符号表截图
    看到这个,我纳闷了~

明明两种声明编译后的结果一样啊,并且都还在同一个数据段(SECT4),对外类型也是默认的External,本质上都是char *

符号表展示出来的结果确实如此,那接着看,看数据段上是怎么说明的。

数据段是包含一个数据头和段落数据,一个obj文件中有多个数据段,每一个数据段都有自己的特性,包括权限、物理地址、数据大小、重定为,行号等,如下为 SECTION HEADER #4的段落头:
SECTION HEADER #4
基本上,从段落头我们就能看到当前数据段的一些大致信息,比如当前段落是.data段(通常包含已初始化的数据)。由于我们对g_strg_str1均进行了初始化,因此,在该段中,可以看到这两个变量。如下图所示,是段落#4的数据段和冲定向段。
RAW DATA #4 & RELOCATIONS #4
在符号表中我们已经看到了,g_strg_str1都是保存在段落4中的。在上图中得以验证,可以看到在RAW DATA中保存了g_str的初始值,在RELOCATIONS中保存了g_str1的初始值,并且加了其他的描述符在其前后,同时,还是以string类型进行编译的。
?

  • RAW DATA :段落数据。每个段落真正数据保存的位置
  • RELOCATIONS: 重定向段。描述文件中符号的重定向信息。
    ?

结合以上所看到的段落信息,说明一下:

由此,我们就可以看到,g_str的数据是保存在.data段的数据段(RAW DATA)的,而.data段的权限是Read Write,这也就说明,g_str是可以被.text(通常包含可执行代码)段操作的,准确说是当前文件的.text段。
?
g_str1是以重定向的方式被保存在数据段4中。保存的名字是??_C@_05MCBCHHEJ@world@,那我们就在obj文件中查找一个这个值真正保存的位置在哪。
从符号表查找??_C@_05MCBCHHEJ@world@,显示如下:
??_C@_05MCBCHHEJ@world@查找结果
可以看到其保存在段落5中。回到.obj文件中查看段落5,截图如下:
SECTION HEADER #5

看到段落5之后是不是有一种,守得云开见月明的感觉。数据段保存的是g_str1的源数据world,而数据段的访问权限是Read only

因此,在调用g_strq[0] = '1'的时候,发生了写入访问权限冲突的异常。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:10:05  更:2022-02-28 15:11:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:53:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码