成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++ 面試題:const 全局變量存在 .data 段還是 .bss 段?

開發
const 全局變量會存放在只讀數據段(.rodata),而非.data或.bss段。因為.data段存放可讀寫的已初始化數據,而 const 變量需要保證只讀屬性,編譯器會將其分配到.rodata段。 

這是今年騰訊最新春招實習生的面試題,不知道是面試者總結手誤寫錯了還是面試官就這么問的,這問的就沒有正確答案。 

我們都知道:全局變量和靜態變量一般存放在 .data 或者 .bss 段,具體取決于是否被初始化。 

  • 如果全局變量被顯式初始化為非零值,它們通常放在 .data 段; 
  • 而如果未初始化或者初始化為零,則可能放在 .bss 段。 

.data 段(已初始化數據段):存放顯式初始化且初始值非零的全局變量和靜態變量。 

int global_var = 42;          // 存儲在 .data 段
static int static_var = 10;   // 存儲在 .data 段

.bss 段(未初始化數據段):存放未顯式初始化或初始化為零的全局變量和靜態變量(節省磁盤空間,加載時自動清零)。 

int global_uninit;            // 存儲在 .bss 段
static int static_zero = 0;   // 存儲在 .bss 段(初始化為零)

為什么說節省空間? 

比如,如果一個全局數組很大但未初始化,那么在編譯后的文件中,BSS段可能只是記錄這個數組的大小,而不是實際存儲所有的零值。當程序加載到內存時,系統會根據需要分配內存并清零,這樣在磁盤上的可執行文件就不會包含這些零值的數據,從而減少了文件的大小。 

const 全局變量不一樣

首先 const全局變量必須顯式初始化(否則編譯報錯),因此不存在“未初始化”的情況。 

const 全局變量會存放在只讀數據段(.rodata),而非.data或.bss段。因為.data段存放可讀寫的已初始化數據,而 const 變量需要保證只讀屬性,編譯器會將其分配到.rodata段。 

我們測試驗證下: 

編寫如下測試代碼: 

const int a = 10;
const int b = 0;

int main() 
{
        return 0;
}

然后執行 g++ 1.cpp 生成 a.out, 我們使用 nm 工具查看符號表,可以發現輸出:

0000000000400530 r _ZL1a
0000000000400534 r _ZL1b

這里 r 表示符號位于只讀數據段。 

所以const全局變量若初始化(無論是否為非零),通常位于.rodata段。 

nm輸出中 B b T 這種字符,代表什么意思

在 nm 的輸出中,符號類型通過 大小寫字母 表示符號的存儲位置和屬性。以下是常見符號類型的解釋: 

字母

大小寫

解釋

B

大寫

未初始化的全局變量

b

小寫

未初始化的靜態變量

T

大寫

全局函數/代碼

t

小寫

靜態函數/代碼

r

小寫

只讀數據

D

大寫

已初始化的全局變量

d

小寫

已初始化的靜態變量

U

大寫

未定義符號

關鍵區別:

  • 大寫字母(B/T/D):表示符號是全局的(全局變量或函數),可以被其他文件訪問。
  • 小寫字母(b/t/d):表示符號是局部的或靜態的(作用域限于當前文件)。
  • 大小寫 B/b:都位于 .bss 段,但作用域不同(大寫為全局,小寫為靜態)。
  • 大小寫 T/t:都位于 .text 段,但作用域不同(大寫為全局函數,小寫為靜態函數)。

我們寫個測試代碼再驗證下: 

const int a = 10; //const 初始化
constint b = 0;//const 初始化為0

int c; //全局 未初始化
int d = 9; //全局 初始化
int dd = 0; //全局 初始化0

staticint e; //靜態 未初始化
staticint f = 10; //靜態初始化
staticint g = 0; //靜態初始化0 

intmain()
{
        return0;
}

編譯后用 nm 查看: 

nm a.out
0000000000601024 B __bss_start
0000000000601028 B c
0000000000601024 b completed.7247
000000000060101c D d
0000000000601018 D __data_start
0000000000601018 W data_start
000000000060102c B dd
0000000000400400 t deregister_tm_clones
0000000000400470 t __do_global_dtors_aux
0000000000600e28 t __do_global_dtors_aux_fini_array_entry
0000000000400528 R __dso_handle
0000000000600e30 d _DYNAMIC
0000000000601024 D _edata
0000000000601038 B _end
0000000000400514 T _fini
00000000004004a0 t frame_dummy
0000000000600e20 t __frame_dummy_init_array_entry
000000000040062c r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
0000000000400538 r __GNU_EH_FRAME_HDR
00000000004003b8 T _init
0000000000600e28 t __init_array_end
0000000000600e20 t __init_array_start
0000000000400520 R _IO_stdin_used
0000000000400510 T __libc_csu_fini
00000000004004b0 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
00000000004004a2 T main
0000000000400430 t register_tm_clones
00000000004003d0 T _start
0000000000601028 D __TMC_END__
0000000000400530 r _ZL1a
0000000000400534 r _ZL1b
0000000000601030 b _ZL1e
0000000000601020 d _ZL1f
0000000000601034 b _ZL1g

這是截圖證明上面不是我虛造的:

可以發現: 

  • a b 前面的符號是 r,表示存放在 .rodata 段 
  • e g 前面的符號是 b,表示存放在 .bss 段 
  • f 前面的符號是 d,表示存放在 .data 段 
  • c dd 前面的符號是 B ,表示存放在 .bss 段 
  • D 前面的符號是 D,表示存放在 .data 段 

所以總結就是:

  • .bss 段:未初始化或零初始化的全局/靜態變量(B 和 b)。
  • .text 段:可執行代碼(T 和 t)。
  • .rodata 段:只讀數據(r)。
  • .data 段:已初始化的全局/靜態變量(D 和 d)。

rodata 段在內存哪個位置呢?

答案是:在程序的內存布局中,.rodata 段(只讀數據段) 通常位于 代碼段(.text)和數據段(.data/.bss)之間。 

我們看前面nm 輸出中,.rodata 段的符號地址集中在 0x400520 到 0x40062c 范圍內: 

0000000000400520 R _IO_stdin_used     # .rodata 起始附近
0000000000400530 r _ZL1a             # const int a = 10
0000000000400534 r _ZL1b             # const int b = 0
000000000040062c r __FRAME_END__     # .rodata 結束附近

(1) .rodata 段地址范圍:0x400520 ~ 0x40062c 該段緊鄰代碼段(.text 段),代碼段的符號地址(如 _start、main 等)在 0x4003d0 ~ 0x400514 之間 

(2) .data 和 .bss 段地址范圍: 

  • .data 段地址:0x6001018 ~ 0x6001020 
  • .bss 段地址:0x6001020 ~ 0x6001030 這些段位于高地址區域(0x60...),與 .rodata 段(0x40...)明顯分離。 

這種布局體現為: 

低地址(0x400000) → 高地址(0x600000)
.text → .rodata → ... → .data → .bss

為什么 .rodata 和 .text 都在 0x40... 地址?

  • 權限隔離: .text(代碼)和 .rodata(只讀數據)通常被標記為 可讀+可執行(r-x),而 .data 和 .bss 被標記為 可讀+可寫(rw-)。 操作系統會將權限相同的段映射到相鄰區域,因此 .rodata 與 .text 位于同一地址范圍內(0x40...)。 
  • 優化內存使用: 將只讀數據與代碼相鄰,可以減少內存碎片,提高緩存命中率。 

驗證 .rodata 的物理位置

可以通過 readelf工具直接查看段頭信息: 

readelf -S a.out

輸出示例(關鍵部分): 

[11] .text             PROGBITS         00000000004003d0  000003d0
       0000000000000141  0000000000000000  AX       0     0     16
[12] .fini             PROGBITS         0000000000400514  00000514
       0000000000000009  0000000000000000  AX       0     0     4
[13] .rodata           PROGBITS         0000000000400520  00000520
       0000000000000018  0000000000000000   A       0     0     8
[21] .data             PROGBITS         0000000000601018  00001018
       000000000000000c  0000000000000000  WA       0     0     4
[22] .bss              NOBITS           0000000000601024  00001024
       0000000000000014  0000000000000000  WA       0     0     4

.rodata 的物理地址:0x400520,與 nm 輸出的符號地址一致。 

完整信息這里也放出來:

readelf -S a.out
There are34 section headers, starting atoffset0x2708:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             000000000000000000000000
       00000000000000000000000000000000           0     0     0
  [ 1] .interp           PROGBITS         000000000040023800000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             000000000040025400000254
       00000000000000200000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             000000000040027400000274
       00000000000000240000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         000000000040029800000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       00000000000000480000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           000000000040030000000300
       000000000000005f  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           000000000040036000000360
       00000000000000060000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          000000000040036800000368
       00000000000000200000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             000000000040038800000388
       00000000000000300000000000000018   A       5     0     8
  [10] .init             PROGBITS         00000000004003b8  000003b8
       00000000000000170000000000000000  AX       0     0     4
  [11] .text             PROGBITS         00000000004003d0  000003d0
       00000000000001410000000000000000  AX       0     0     16
  [12] .fini             PROGBITS         000000000040051400000514
       00000000000000090000000000000000  AX       0     0     4
  [13] .rodata           PROGBITS         000000000040052000000520
       00000000000000180000000000000000   A       0     0     8
  [14] .eh_frame_hdr     PROGBITS         000000000040053800000538
       000000000000002c  0000000000000000   A       0     0     4
  [15] .eh_frame         PROGBITS         000000000040056800000568
       00000000000000c8  0000000000000000   A       0     0     8
  [16] .init_array       INIT_ARRAY       0000000000600e2000000e20
       00000000000000080000000000000008  WA       0     0     8
  [17] .fini_array       FINI_ARRAY       0000000000600e2800000e28
       00000000000000080000000000000008  WA       0     0     8
  [18] .dynamic          DYNAMIC          0000000000600e3000000e30
       00000000000001c0  0000000000000010  WA       6     0     8
  [19] .got              PROGBITS         0000000000600ff0  00000ff0
       00000000000000100000000000000008  WA       0     0     8
  [20] .got.plt          PROGBITS         000000000060100000001000
       00000000000000180000000000000008  WA       0     0     8
  [21] .data             PROGBITS         000000000060101800001018
       000000000000000c  0000000000000000  WA       0     0     4
  [22] .bss              NOBITS           000000000060102400001024
       00000000000000140000000000000000  WA       0     0     4
  [23] .comment          PROGBITS         000000000000000000001024
       000000000000002c  0000000000000001  MS       0     0     1
  [24] .debug_aranges    PROGBITS         000000000000000000001050
       00000000000001000000000000000000           0     0     16
  [25] .debug_info       PROGBITS         000000000000000000001150
       00000000000003130000000000000000           0     0     1
  [26] .debug_abbrev     PROGBITS         000000000000000000001463
       00000000000001950000000000000000           0     0     1
  [27] .debug_line       PROGBITS         0000000000000000000015f8
       000000000000023f  0000000000000000           0     0     1
  [28] .debug_str        PROGBITS         000000000000000000001837
       00000000000002bd  0000000000000001  MS       0     0     1
  [29] .debug_loc        PROGBITS         000000000000000000001af4
       00000000000001550000000000000000           0     0     1
  [30] .debug_ranges     PROGBITS         000000000000000000001c50
       00000000000000800000000000000000           0     0     16
  [31] .symtab           SYMTAB           000000000000000000001cd0
       00000000000007080000000000000018          32    56     8
  [32] .strtab           STRTAB           0000000000000000000023d8
       00000000000001d8  0000000000000000           0     0     1
  [33] .shstrtab         STRTAB           0000000000000000000025b0
       00000000000001520000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

.rodata段與其他段的關系

段名

內容

讀寫權限

位置特征

.text

可執行代碼

只讀 + 可執行

最低地址區域

.rodata

只讀常量(如

只讀

緊鄰

.data

已初始化全局/靜態變量

可讀寫

高于

.bss

未初始化全局/靜態變量

可讀寫

緊鄰

總結

  • 答案:const 全局變量既不在 .data 段也不在 .bss 段,而是在 .rodata 段 
  • 位置:.rodata 段位于 代碼段(.text)和數據段(.data/.bss)之間。 
  • 權限:與代碼段共享只讀屬性,但不可執行。 
責任編輯:趙寧寧 來源: CppPlayer
相關推薦

2025-06-05 08:05:00

vectorC++對象存儲

2013-07-22 14:07:47

2021-10-27 11:00:30

C++語言面試

2010-02-02 14:06:50

C++ const變量

2025-06-03 08:50:00

Static全局變量C 語言

2025-05-23 08:15:00

C++constexpr字面類型

2025-05-26 03:20:00

2025-05-20 10:00:00

C++命名空間別名代碼

2025-05-06 08:20:00

互斥鎖C++編程

2011-03-29 14:31:41

CC++

2025-05-27 10:15:00

void*函數開發

2025-04-30 10:10:00

在 C++C++11Lambda

2010-11-12 10:08:55

SQL Server全

2013-07-25 15:15:26

iOS開發學習iOS全局變量

2013-07-17 16:16:06

Android全局變量定義全局變量Application

2009-09-07 15:15:43

2025-05-20 08:10:00

函數函數類型函數指針類型

2020-06-04 14:40:40

面試題Vue前端

2022-04-12 11:38:06

C語言全局變量

2010-03-09 14:12:55

Python全局變量
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 人妖一区 | 欧美二区三区 | 精品久久久久久 | 男人av网| 国产高清视频在线观看 | 国产欧美精品一区二区 | 伊人久久大香线 | 91视频国产精品 | 久久久久国产精品午夜一区 | 久久久九九九九 | 亚洲精品一区二区三区免 | 五月激情综合网 | 亚洲精品一区二区三区丝袜 | 中文字幕91 | 婷婷在线视频 | 综合久久亚洲 | 国产一区二区在线免费 | 国产欧美日韩一区二区三区在线 | 国产精品99久久久久久久vr | 伊人久久精品一区二区三区 | 久草精品视频 | 久久久久久免费观看 | 亚洲一区二区视频在线观看 | 毛色毛片免费看 | 一区二区三区国产视频 | 国产二区精品视频 | 武道仙尊动漫在线观看 | 九色 在线 | 国产97视频在线观看 | av先锋资源| 黄色一级视频免费 | 成人h动漫精品一区二区器材 | 日本在线看 | 国产欧美精品 | 日韩欧美成人一区二区三区 | 免费成年网站 | 欧美日韩成人在线观看 | 丁香久久 | 免费性视频 | 欧美黄色网络 | 一区在线观看 |