簡體   English   中英

C ++浮點常量是否總是存儲在靜態內存中?

[英]Are C++ floating point constants always stored in static memory?

在他的《 用C ++優化軟件》一書中 Agner Fog提供了以下示例:

字符串常量和浮點常量存儲在靜態內存中。 例:

 // Example 7.2 a = b * 3.5; c = d + 3.5; 

在這里,常數3.5將存儲在靜態存儲器中。 大多數編譯器會認識到兩個常量是相同的,因此只需要存儲一個常量。

所有浮點常量是否總是存儲在靜態存儲器中?

為什么不能將它們存儲在堆棧中 說出他給出的例子。

我根據您的偽代碼創建了一個簡單的工作示例:

int main()
{
  double b = 3.0;
  double d = 3.14;
  double a = b * 3.5;
  double c = d + 3.5;
  return 0;
}

然后編譯它:

g++ -O0 -o const const.cc

然后在調試器中使用它:

gdb const
...
(gdb) disass main
Dump of assembler code for function main:
   0x00000000004004ed <+0>: push   %rbp
   0x00000000004004ee <+1>: mov    %rsp,%rbp
   0x00000000004004f1 <+4>: movabs $0x4008000000000000,%rax
   0x00000000004004fb <+14>:    mov    %rax,-0x20(%rbp)
   0x00000000004004ff <+18>:    movabs $0x40091eb851eb851f,%rax
   0x0000000000400509 <+28>:    mov    %rax,-0x18(%rbp)
   0x000000000040050d <+32>:    movsd  -0x20(%rbp),%xmm1
   0x0000000000400512 <+37>:    movsd  0xae(%rip),%xmm0        # 0x4005c8
   0x000000000040051a <+45>:    mulsd  %xmm1,%xmm0
   0x000000000040051e <+49>:    movsd  %xmm0,-0x10(%rbp)
   0x0000000000400523 <+54>:    movsd  -0x18(%rbp),%xmm1
   0x0000000000400528 <+59>:    movsd  0x98(%rip),%xmm0        # 0x4005c8
   0x0000000000400530 <+67>:    addsd  %xmm1,%xmm0
   0x0000000000400534 <+71>:    movsd  %xmm0,-0x8(%rbp)
   0x0000000000400539 <+76>:    mov    $0x0,%eax
   0x000000000040053e <+81>:    pop    %rbp
   0x000000000040053f <+82>:    retq   
End of assembler dump.
(gdb) b main
Breakpoint 1 at 0x4004f1
(gdb) r
Starting program: /home/sasha/stackoverflow/const 

Breakpoint 1, 0x00000000004004f1 in main ()
(gdb) p  *(double*)0x4005c8
$2 = 3.5

因此,您可以從所有這些中看到常量3.5存儲在地址0x4005c8處,該地址0x4005c8 main末尾僅136個字節之后。 兩次都使用相同的地址來引用它,盡管它在反匯編中的顯示方式有所不同-第一次是0xae(%rip) ,第二次是movsd 0x98(%rip) 這是因為rip的值隨着執行的進行而不斷變化-它是指令指針。

objdump -t的幫助下,您可以看到上述地址屬於.rodata部分。

請注意,分別對3.0和3.14常量進行顯式編碼,而無需使用內存引用:

movabs $0x4008000000000000,%rax

movabs $0x40091eb851eb851f,%rax

顯然,由於不再重復它們,因此gcc決定將它們存儲在內存中是不值得的。

更新:正如JSF所指出的,決定不使用存儲的內存而不是立即常量的決定確實取決於用法。 我驗證了是否將double d = 3.14更改為double d = b + 3.14 3.14成為內存引用。

我使用-O0來使事情保持簡單。 在這樣一個簡單的示例中進行優化,就可以將裝配體優化為可以達到相同結果的東西,但是其方式與足以說明問題的東西相去甚遠。

至少在gcc的情況下,答案似乎確實是“取決於”。 但是,如果您很好奇,而不是僅僅相信一本書或一篇博客文章,那么最好舉一個簡單的例子並將其拆開-您可以從馬口中直接得到它,並且學到很多東西。

謝謝你的例子。 沒錯,當使用gcc為64位模式關閉優化(-O0)時,它將常量存儲在代碼中。 如果您為32位模式進行編譯,它將常數存儲在內存中。

如果啟用優化(-O3),則會簡單地優化計算,因為它們沒有使用,並且main只會返回0。

如果您創建一個執行一些浮點計算並返回浮點數或雙精度數的函數,並且在啟用優化的情況下進行編譯,那么您會看到浮點常量存儲在靜態內存中。

我嘗試了這個:

float test(float x) {
    return x*0.9f + 3.1f;
}

g ++ -c -S -O3 test.cpp

貓測試

並得到:

mulss   .LC0(%rip), %xmm0
addss   .LC1(%rip), %xmm0
ret

其中.LC0和.LC1是只讀數據段中的常量。 x86和x86-64指令集沒有(不幸的)沒有指令將立即數存儲在浮點寄存器或向量寄存器中。 它必須首先將常量存儲在通用寄存器中,然后將其傳輸到xmm寄存器中,這並不是最佳選擇(除非數據高速緩存上的負載很重,而代碼高速緩存上的負載很重)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM