33.1.2 std::string 作为全局变量使用

有经验的c++程序员会说,可以定义一个STL类型的全局变量。 是的,确实如此

  1. #include <stdio.h>
  2. #include <string>
  3. std::string s="a string";
  4. int main()
  5. {
  6. printf ("%s\n", s.c_str());
  7. };
  1. MSVC
  2. $SG39512 DB a string’, 00H
  3. $SG39519 DB ’%s’, 0aH, 00H
  4. _main PROC
  5. cmp DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  6. +20, 16 ; 00000010H
  7. mov eax, OFFSET ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  8. ; s
  9. cmovae eax, DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?
  10. $allocator@D@2@@std@@A
  11. push eax
  12. push OFFSET $SG39519
  13. call _printf
  14. add esp, 8
  15. xor eax, eax
  16. ret 0
  17. _main ENDP
  18. ??__Es@@YAXXZ PROC ; dynamic initializer for s’’, COMDAT
  19. push 8
  20. push OFFSET $SG39512
  21. mov ecx, OFFSET ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  22. ; s
  23. call ?assign@?$basic_string@DU?$char_traits@D@std@@V?
  24. $allocator@D@2@@std@@QAEAAV12@PBDI@Z ; std::basic_string<char,std::char_traits<char>,std::
  25. allocator<char> >::assign
  26. push OFFSET ??__Fs@@YAXXZ ; dynamic atexit destructor for s’’
  27. call _atexit
  28. pop ecx
  29. ret 0
  30. ??__Es@@YAXXZ ENDP ; dynamic initializer for s’’
  31. ??__Fs@@YAXXZ PROC ; dynamic atexit destructor for s’’,
  32. COMDAT
  33. push ecx
  34. cmp DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  35. +20, 16 ; 00000010H
  36. jb SHORT $LN23@dynamic
  37. push esi
  38. mov esi, DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?
  39. $allocator@D@2@@std@@A
  40. lea ecx, DWORD PTR $T2[esp+8]
  41. call ??0?$_Wrap_alloc@V?$allocator@D@std@@@std@@QAE@XZ ; std::_Wrap_alloc<std::
  42. allocator<char> >::_Wrap_alloc<std::allocator<char> >
  43. push OFFSET ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A ; s
  44. lea ecx, DWORD PTR $T2[esp+12]
  45. call ??$destroy@PAD@?$_Wrap_alloc@V?$allocator@D@std@@@std@@QAEXPAPAD@Z ; std::
  46. _Wrap_alloc<std::allocator<char> >::destroy<char *>
  47. lea ecx, DWORD PTR $T1[esp+8]
  48. call ??0?$_Wrap_alloc@V?$allocator@D@std@@@std@@QAE@XZ ; std::_Wrap_alloc<std::
  49. allocator<char> >::_Wrap_alloc<std::allocator<char> >
  50. push esi
  51. call ??3@YAXPAX@Z ; operator delete
  52. add esp, 4
  53. pop esi
  54. $LN23@dynamic:
  55. mov DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  56. +20, 15 ; 0000000fH
  57. mov DWORD PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A
  58. +16, 0
  59. mov BYTE PTR ?s@@3V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A, 0
  60. pop ecx
  61. ret 0
  62. ??__Fs@@YAXXZ ENDP ; dynamic atexit destructor for s’’

实际上,main函数之前,CRT中将调用一个特殊的函数调用所有全局变量的构造函数。除此之外,CRT中还将通过atexit()注册另一个函数,该函数中将调用全局变量的析构函数。 GCC生成的代码如下:

  1. main:
  2. push ebp
  3. mov ebp, esp
  4. and esp, -16
  5. sub esp, 16
  6. mov eax, DWORD PTR s
  7. mov DWORD PTR [esp], eax
  8. call puts
  9. xor eax, eax
  10. leave
  11. ret
  12. .LC0:
  13. .string "a string"
  14. _GLOBAL__sub_I_s:
  15. sub esp, 44
  16. lea eax, [esp+31]
  17. mov DWORD PTR [esp+8], eax
  18. mov DWORD PTR [esp+4], OFFSET FLAT:.LC0
  19. mov DWORD PTR [esp], OFFSET FLAT:s
  20. call _ZNSsC1EPKcRKSaIcE
  21. mov DWORD PTR [esp+8], OFFSET FLAT:__dso_handle
  22. mov DWORD PTR [esp+4], OFFSET FLAT:s
  23. mov DWORD PTR [esp], OFFSET FLAT:_ZNSsD1Ev
  24. call __cxa_atexit
  25. add esp, 44
  26. ret
  27. .LFE645:
  28. .size _GLOBAL__sub_I_s, .-_GLOBAL__sub_I_s
  29. .section .init_array,"aw"
  30. .align 4
  31. .long _GLOBAL__sub_I_s
  32. .globl s
  33. .bss
  34. .align 4
  35. .type s, @object
  36. .size s, 4
  37. s:
  38. .zero 4
  39. .hidden __dso_handle

GCC并没有创建单独的函数来玩全局变量的析构,而是依次将全局变量的析构函数传递给atexit()函数