【Qt开发】关于Qt应用程序中的堆栈、静态存储区的使用错误

admin 2022年7月1日00:04:11评论41 views字数 10126阅读33分45秒阅读模式
最近终于又碰到了这个问题,想在main函数中定义一个局部大的数组,结果运行就报错,尼玛!刚开始真的不知道到发生了什么,后来一步一步的试,锁定在这个大的数组上。在主函数里定义的局部变量应该是在栈区保存的,难道是Qt默认的栈不够所致。

后来改为new或者malloc,也就是从堆里面申请内存,程序就没问题,或者是定义全局变量应该是放在了全局静态存储区,都是可以的,不报错!

所以牢记这一点!!

下面还是经典的经典内存分布说明:

一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(.data),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(.bss)。- 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的(.rodata)。程序结束后由系统释放。
5、程序代码区—存放函数体的二进制代码(.text)。

二、例子程序
这是一个前辈写的,非常详细

//main.cppint a = 0;          // 全局初始化区char *p1;           // 全局未初始化区main(){  int b;            // 栈区  char s[] = "abc"; // 栈区  char *p2;         // 栈区  char *p3 = "123456";     // "123456/0" 在常量区,p3在栈区  static int c =0;         // 全局(静态)初始化区
p1 = (char *)malloc(10); p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在堆区
strcpy(p1, "123456"); // "123456/0" 放在常量区,编译器可能会将它 // 与p3所指向的"123456"优化成一个地方。}

==============================================================

static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?  
答:
1) 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
2) 从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。  
3) static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件   
综上所述:
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;   
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;  
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

==============================================================
一个C语言变量分配的实际例子:

我们来看看在可执行文件中,变量们会被分配在哪些区里.这里以可执行文件为例子,可执行文件有固定的内存加载地址,符号(函数/变量的名字)将来在内存里的地址连接器是可以提前确定的。

源程序编译连接的结果是形成1堆汇编指令代码,大致分为.text .data .bss等几个节区(section)。对于.exe文件和.so文件,全局和静态变量都放在.data 或.bss段(gas把源文件从头到尾扫描1遍,才知道一个变量的全部情况:是否定义;类型;是否初始化。然后把初始化的变量在.data段里分配位置和 空间,把没初始化的变量在.bss段里分配位置和空间,没定义的变量分配在.undef段)。汇编指令代码里全局变量表现为一个内存地址(全局变量在目标 文件里是一个偏移值,加载进内存里是一个内存地址)。临时变量在汇编代码里变成ebp/esp+n,表现为一个堆栈地址,化为程序正文(.text)的一 部分。有些变量的最终内存地址在加载进内存之前还不能确定,需要加载进内存才可以计算出来.
全局变量 作用域是跨越多个源程序的。因此全局变量不能重名。静态变量作用域是位于单个源程序内。多个源程序可以有同名的全局静态变量。本例中,为了区分多个同名的静态变量,gcc 用 c444和c444.0 来加以区别。

[test@redhat]# more aaa.c# include int a111 = 0;              # 全局变量 已初始化char *p111 = "654321";     # 全局指针变量 已经初始化static int c444 = 9;       # 静态全局变量 已经初始化static int c555;           # 静态全局变量 未初始化main() {     int b222;              # 局部变量    char s333[] = "abc";   # 局部变量    char *p222;            # 局部变量    char *p333 = "123456";    # 局部变量    static int c444 =0;       # 已初始化静态局部变量,与前面静态全局变量重名p111 = (char *)malloc(10); p222 = (char *)malloc(20);strcpy(p111, "123456");}

[test@redhat]# gcc -o aaa ./aaa.c
[test@redhat]# readelf -a ./aaaELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x80482d0 Start of program headers: 52 (bytes into file) Start of section headers: 2040 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 7 Size of section headers: 40 (bytes) Number of section headers: 27 Section header string table index: 24

Section Headers: Addr是文件加载进内存时,每个section在内存中的虚拟地址

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al  [ 0]                   NULL            00000000 000000 000000 00      0   0  0  [ 1] .interp           PROGBITS        08048114 000114 000013 00   A  0   0  1  [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4  [ 3] .hash             HASH            08048148 000148 00002c 04   A  4   0  4  [ 4] .dynsym           DYNSYM          08048174 000174 000060 10   A  5   1  4  [ 5] .dynstr           STRTAB          080481d4 0001d4 000053 00   A  0   0  1  [ 6] .gnu.version      VERSYM          08048228 000228 00000c 02   A  4   0  2  [ 7] .gnu.version_r    VERNEED         08048234 000234 000020 00   A  5   1  4  [ 8] .rel.dyn          REL             08048254 000254 000008 08   A  4   0  4  [ 9] .rel.plt          REL             0804825c 00025c 000018 08   A  4   b  4  [10] .init             PROGBITS        08048274 000274 000017 00  AX  0   0  4  [11] .plt              PROGBITS        0804828c 00028c 000040 04  AX  0   0  4  [12] .text             PROGBITS        080482d0 0002d0 0001e4 00  AX  0   0 16  [13] .fini             PROGBITS        080484b4 0004b4 00001b 00  AX  0   0  4  [14] .rodata           PROGBITS        080484d0 0004d0 00001a 00   A  0   0  4  [15] .eh_frame         PROGBITS        080484ec 0004ec 000004 00   A  0   0  4  [16] .data             PROGBITS        080494f0 0004f0 00001c 00  WA  0   0  4  [17] .dynamic          DYNAMIC         0804950c 00050c 0000c8 08  WA  5   0  4  [18] .ctors            PROGBITS        080495d4 0005d4 000008 00  WA  0   0  4  [19] .dtors            PROGBITS        080495dc 0005dc 000008 00  WA  0   0  4  [20] .jcr              PROGBITS        080495e4 0005e4 000004 00  WA  0   0  4  [21] .got              PROGBITS        080495e8 0005e8 00001c 04  WA  0   0  4  [22] .bss              NOBITS          08049604 000604 000008 00  WA  0   0  4  [23] .comment          PROGBITS        00000000 000604 000126 00      0   0  1  [24] .shstrtab         STRTAB          00000000 00072a 0000ce 00      0   0  1  [25] .symtab           SYMTAB          00000000 000c30 0004c0 10     26  2f  4  [26] .strtab           STRTAB          00000000 0010f0 000275 00      0   0  1Program Headers:  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align  PHDR           0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4  INTERP         0x000114 0x08048114 0x08048114 0x00013 0x00013 R   0x1      [Requesting program interpreter: /lib/ld-linux.so.2]  LOAD           0x000000 0x08048000 0x08048000 0x004f0 0x004f0 R E 0x1000  LOAD           0x0004f0 0x080494f0 0x080494f0 0x00114 0x0011c RW  0x1000  DYNAMIC        0x00050c 0x0804950c 0x0804950c 0x000c8 0x000c8 RW  0x4  NOTE           0x000128 0x08048128 0x08048128 0x00020 0x00020 R   0x4  STACK          0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4

Symbol table ‘.symtab’ contains 76 entries:

对于.exe文件,符号的Value 是将来加载进内存中的真实地址;对于.so文件Value需要重定位.

 Num:    Value  Size Type    Bind   Vis      Ndx Name     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND      1: 08048114     0 SECTION LOCAL  DEFAULT    1      2: 08048128     0 SECTION LOCAL  DEFAULT    2      3: 08048148     0 SECTION LOCAL  DEFAULT    3      4: 08048174     0 SECTION LOCAL  DEFAULT    4      5: 080481d4     0 SECTION LOCAL  DEFAULT    5      6: 08048228     0 SECTION LOCAL  DEFAULT    6      7: 08048234     0 SECTION LOCAL  DEFAULT    7      8: 08048254     0 SECTION LOCAL  DEFAULT    8      9: 0804825c     0 SECTION LOCAL  DEFAULT    9     10: 08048274     0 SECTION LOCAL  DEFAULT   10     11: 0804828c     0 SECTION LOCAL  DEFAULT   11     12: 080482d0     0 SECTION LOCAL  DEFAULT   12     13: 080484b4     0 SECTION LOCAL  DEFAULT   13     14: 080484d0     0 SECTION LOCAL  DEFAULT   14     15: 080484ec     0 SECTION LOCAL  DEFAULT   15     16: 080494f0     0 SECTION LOCAL  DEFAULT   16     17: 0804950c     0 SECTION LOCAL  DEFAULT   17     18: 080495d4     0 SECTION LOCAL  DEFAULT   18     19: 080495dc     0 SECTION LOCAL  DEFAULT   19     20: 080495e4     0 SECTION LOCAL  DEFAULT   20     21: 080495e8     0 SECTION LOCAL  DEFAULT   21     22: 08049604     0 SECTION LOCAL  DEFAULT   22     23: 00000000     0 SECTION LOCAL  DEFAULT   23     24: 00000000     0 SECTION LOCAL  DEFAULT   24     25: 00000000     0 SECTION LOCAL  DEFAULT   25     26: 00000000     0 SECTION LOCAL  DEFAULT   26     27: 080482f4     0 FUNC    LOCAL  DEFAULT   12 call_gmon_start    28: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c    29: 080495d4     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__    30: 080495dc     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__    31: 080484ec     0 OBJECT  LOCAL  DEFAULT   15 __EH_FRAME_BEGIN__    32: 080495e4     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__    33: 080494f8     0 OBJECT  LOCAL  DEFAULT   16 p.0    34: 08049604     1 OBJECT  LOCAL  DEFAULT   22 completed.1    35: 08048320     0 FUNC    LOCAL  DEFAULT   12 __do_global_dtors_aux    36: 08048360     0 FUNC    LOCAL  DEFAULT   12 frame_dummy    37: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c    38: 080495d8     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__    39: 080495e0     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_END__    40: 080484ec     0 OBJECT  LOCAL  DEFAULT   15 __FRAME_END__    41: 080495e4     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__    42: 08048490     0 FUNC    LOCAL  DEFAULT   12 __do_global_ctors_aux    43: 00000000     0 FILE    LOCAL  DEFAULT  ABS aaa.c    44: 08049504     4 OBJECT  LOCAL  DEFAULT   16 c444   # static变量为LOCAL绑定属性(也即作用域) 已初始化静态变量存放在.data    45: 08049508     4 OBJECT  LOCAL  DEFAULT   16 c444.0 # 已初始化静态变量存放在.data (多个源文件可以定义同名的静态变量)    46: 08049608     4 OBJECT  LOCAL  DEFAULT   22 c555   # 未初始化静态变量存放在.bss    47: 080494fc     4 OBJECT  GLOBAL DEFAULT   16 a111   # 全局变量为GLOBAL绑定属性  已初始全局变量存放在.data    48: 0804950c     0 OBJECT  GLOBAL DEFAULT   17 _DYNAMIC    49: 080484d0     4 OBJECT  GLOBAL DEFAULT   14 _fp_hw    50: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __fini_array_end    51: 080494f4     0 OBJECT  GLOBAL HIDDEN   16 __dso_handle    52: 08048440    66 FUNC    GLOBAL DEFAULT   12 __libc_csu_fini    53: 08048274     0 FUNC    GLOBAL DEFAULT   10 _init    54: 0804829c   427 FUNC    GLOBAL DEFAULT  UND malloc@@GLIBC_2.0     55: 080482d0     0 FUNC    GLOBAL DEFAULT   12 _start    56: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __fini_array_start    57: 080483f0    71 FUNC    GLOBAL DEFAULT   12 __libc_csu_init    58: 08049500     4 OBJECT  GLOBAL DEFAULT   16 p111    59: 08049604     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start    60: 0804838c    89 FUNC    GLOBAL DEFAULT   12 main    61: 080482ac   251 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC _    62: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __init_array_end    63: 080494f0     0 NOTYPE  WEAK   DEFAULT   16 data_start    64: 080484b4     0 FUNC    GLOBAL DEFAULT   13 _fini    65: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __preinit_array_end    66: 08049604     0 NOTYPE  GLOBAL DEFAULT  ABS _edata    67: 080495e8     0 OBJECT  GLOBAL DEFAULT   21 _GLOBAL_OFFSET_TABLE_    68: 0804960c     0 NOTYPE  GLOBAL DEFAULT  ABS _end    69: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __init_array_start    70: 080484d4     4 OBJECT  GLOBAL DEFAULT   14 _IO_stdin_used    71: 080494f0     0 NOTYPE  GLOBAL DEFAULT   16 __data_start    72: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses    73: 080494f0     0 NOTYPE  GLOBAL HIDDEN  ABS __preinit_array_start    74: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__    75: 080482bc    48 FUNC    GLOBAL DEFAULT  UND strcpy@@GLIBC_2.0
文件./aaa加载进内存后,再看看变量的地址以及所在的区:
[test@redhat]# gdb ./aaaGNU gdb 6.1.1(gdb) disassemble mainDump of assembler code for function main:0x0804838c <main+0</main+>:    push   %ebp0x0804838d <main+1</main+>:    mov    %esp,%ebp0x0804838f <main+3</main+>:    sub    $0x18,%esp0x08048392 <main+6>:    and    $0xfffffff0,%esp0x08048395 <main+9>:    mov    $0x0,%eax0x0804839a <main+14>:   sub    %eax,%esp# char s333[] = "abc";0x0804839c <main+16</main+>:   mov    0x80484df,%eax            # 0x80484df处为"abc",位于.rodata0x080483a1 <main+21</main+>:   mov    %eax,0xfffffff8(%ebp)     # 0xfffffff8(%ebp) 为局部变量 char s333[]# char *p333 = "123456";0x080483a4 <main+24</main+>:   movl   $0x80484e3,0xfffffff0(%ebp)  # 0x80484e3处为"123456/0",位于.rodata; 0xfffffff0(%ebp) 为局部变量 char *p333# p111 = (char *)malloc(10);0x080483ab <main+31</main+>:   sub    $0xc,%esp0x080483ae <main+34>:   push   $0xa          # 0xa=10 ; push $0xa后,此时堆栈esp值又减去4字节,相当于sub $0x10,%esp0x080483b0 <main+36>:   call   0x804829c <malloc>0x080483b5 <main+41>:   add    $0x10,%esp0x080483b8 <main+44>:   mov    %eax,0x8049500  # 0x8049500 为全局变量p111,位于.data# p222 = (char *)malloc(20);0x080483bd <main+49</main+>:   sub    $0xc,%esp0x080483c0 <main+52>:   push   $0x14        # 0x14=20 ; push $0xa后,此时堆栈esp值又减去4字节,相当于sub $0x10,%esp0x080483c2 <main+54>:   call   0x804829c <malloc>0x080483c7 <main+59>:   add    $0x10,%esp0x080483ca <main+62>:   mov    %eax,0xfffffff4(%ebp)  # 0xfffffff4(%ebp) 为局部变量p222# strcpy(p111, "123456");0x080483cd <main+65</main+>:   sub    $0x8,%esp0x080483d0 <main+68>:   push   $0x80484e3    # 0x80484e3处内容为"123456/0",位于.rodata; 0x080483d5 <main+73</main+>:   pushl  0x8049500     # 0x8049500 为全局变量p111,位于.data0x080483db <main+79</main+>:   call   0x80482bc 0x080483e0 <main+84</main+>:   add    $0x10,%esp0x080483e3 <main+87</main+>:   leave  0x080483e4 <main+88</main+>:   ret    0x080483e5 <main+89</main+>:   nop    0x080483e6 <main+90</main+>:   nop    0x080483e7 <main+91</main+>:   nop    0x080483e8 <main+92</main+>:   nop    0x080483e9 <main+93</main+>:   nop    0x080483ea <main+94</main+>:   nop    0x080483eb <main+95</main+>:   nop    0x080483ec <main+96</main+>:   nop    0x080483ed <main+97</main+>:   nop    0x080483ee <main+98</main+>:   nop    0x080483ef <main+99</main+>:   nop    End of assembler dump.(gdb) q[test@redhat]#


【Qt开发】关于Qt应用程序中的堆栈、静态存储区的使用错误


原文始发于微信公众号(汇编语言):【Qt开发】关于Qt应用程序中的堆栈、静态存储区的使用错误

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年7月1日00:04:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【Qt开发】关于Qt应用程序中的堆栈、静态存储区的使用错误http://cn-sec.com/archives/1135312.html

发表评论

匿名网友 填写信息