- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
来自类似问题here我看到 constant 变量必须在程序的进程内存 Text 段 中,如果我理解的一切正确 - 它确实是:
int main() {
static const char somedata[8192] = "somedata";
while (1) {
printf("\tAddress of main: %p\n", main);
printf("\tMy process ID : %d\n", getpid());
printf("\tArray Some first address: %p\n", &somedata[1]);
sleep(10);
};
return 0;
}
这给了我结果:
Address of main: 0x4bc38b971a
My process ID : 633
Array Some first address: 0x4bc38b9881
运行后 - /proc/maps
确认:
$ cat /proc/633/maps
4bc38b9000-4bc38bc000 r-xp 00000000 fe:01 19664256
0x4bc38b9881
在 dec 中是 325403252865,0x4bc38b9000 - 0x4bc38bc000
是 325403250688-325403262976,325403252865 在这些边界之间,一切看起来都是正确的。
size
也告诉它在 text
中:
$ size mem_lay_inc_text_print
text data bss dec hex filename
10097 608 8 10713 29d9 mem_lay_inc_text_print
但是this (以及很多类似的)主题说 - constant 在 Initialized Data Segment 而不是在 Code segment 中:
Initialized data stores all global, static, constant,
那么 - 真相在哪里?或者我只是误会了什么?
也许 4bc38b9000-4bc38bc000 包含 Init.数据 和文本 段?
不,它没有:
...
static int i = 100;
while (1) {
printf("Address of main: %p\n", main);
printf("My process ID : %d\n", getpid());
printf("Array Some first address: %p\n", &somedata[1]);
printf("Int I address: %p\n", &i);
...
现在从 size
的结果中我看到 data
变大了(data 612
而不是 608
第一个结果),maps
也表示相同:
...
Int I address: 0xea335af040
...
和 map
:
$ cat /proc/8859/maps
ea333ac000-ea333af000 r-xp 00000000 fe:01 19664256
ea335ae000-ea335af000 r--p 00002000 fe:01 19664256
ea335af000-ea335b0000 rw-p 00003000 fe:01 19664256
0xea335af040 在 ea335af000-ea335b0000 中带有 rw-p
,也就是 data
...
真的很困惑...
$ gcc --version
gcc (GCC) 7.1.1 20170630
所以问题是:常量存储在哪里 - 在初始化数据中,还是在文本段中?还是取决于编译器/操作系统?
最佳答案
由于空间和格式的限制,我更喜欢在这里写一个扩展评论而不是评论。
首先,内存布局链接位于 https://developerinsider.co/memory-layout-representation-of-c-program/没有错;它只是没有提到它正在尝试对所有操作系统进行全面的一般性讨论。四个通用的布局概念是:1) 代码,2) 在构建时分配的数据(这变得困惑),以及两种动态数据:3) 堆栈和 4) 堆。如图所示。它忽略了提及动态链接环境所需的许多实际机制,例如全局偏移表 (.got)。
我认为 OP 模糊的一个重要区别是可执行文件布局与运行进程内存布局。可执行文件布局(例如 ELF)是磁盘上包含进程蓝图的潜在位。这是讨论所有特定部分 以及objdump
工具应用的地方。 objdump -h foo
实际上会显示 30 个部分。
Linux 内核中的可执行加载器将这些许多部分映射到几个内存区域,以最大限度地减少管理内存的复杂性和开销。
下一个重要的区别是通用的 Unix 行为与 Linux 的细节之间的区别,至少在概念上,在廉价硬件上的性能比优雅和坚持干净的分离更重要。因此在引用的链接中:
For that reason, the .rodata section, which contains read-only initialized data, is packed into the same segment that contains the .text section.
这很不幸,因为只读初始化数据附加了完全不必要的执行权限。几乎可以肯定的是,经过强化的 Linux 变体不会以轻微的内存或 CPU 浪费为代价来做到这一点。
这是我的代码(我注意到您使用的是基于 1 的数组——哎呀,这不是 C 的工作方式!)——它试图显示只读与读写映射:
#include <stdio.h> /* printf */
#include <sys/types.h> /* getpid */
#include <unistd.h> /* getpid */
#include <sys/select.h>
const char small_ro_global[ 16] = "small ro global";
char small_rw_global[ 16] = "small ro global";
const char big_ro_global[8192] = " big ro global";
char big_rw_global[8192] = " big rw global";
int main(int argc, char *argv[]) {
/* small_ro_global[1] = 'b'; compile error */
small_rw_global[1] = 'c'; /* ensure writable */
printf("Address of main: %p\n", main);
printf("My process ID : %d\n", getpid());
printf("small_ro_global: %p big_ro_global: %p small_rw_global: %p big_rw_global: %p\n",
small_ro_global, big_ro_global, small_rw_global, big_rw_global);
/* waits forever */
select(0, NULL, NULL, NULL, NULL);
return 0;
}
GCC:v. 4.8.4 GNU/Linux 发行版:Ubuntu 15.10 硬件:Intel 64 位输出:
Address of main: 0x4005cd
My process ID : 5788
small_ro_global: 0x400700 big_ro_global: 0x400720 small_rw_global: 0x603060 big_rw_global: 0x603080
/proc/5788/maps
摘录。请注意第 1 部分和第 3 部分中的内容,但第 2 部分中没有内容:
00400000-00403000 r-xp 00000000 ca:01 1947 /root/foo
00602000-00603000 r--p 00002000 ca:01 1947 /root/foo
00603000-00606000 rw-p 00003000 ca:01 1947 /root/foo
最后,感谢刚刚了解到 readelf -l
的链接,它给出了以下内容。特别是参见包含 .text 和 .rodata 部分的段 02。
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got
从关于proc
(5) 的文档中,我们了解到内存段中的第二个(权限:只读,不可执行),并将其与objdump
,用于流程机制:动态链接和异常处理。它包含以下部分:.eh_frame_hdr
、.eh_frame
、.init_array
、.fini_array
、.jcr
、.dynamic
和 .got
。
因此,您在代码中指向的任何内容都不会在该区域显示。
关于C - 进程内存中的常量在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46014769/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!