簡體   English   中英

將位設置為double並使用g ++的優化標志進行編譯

[英]Setting bits in a double and compiling with optimization flags of g++

我試圖將位設置為雙精度(IEEE標准754)。 說我想'構建'一個3,我會設置雙浮點表示的第51位和第62位,這樣我得到二進制1.1 * 2,十進制是3.我寫了這個簡單的主:

int main() {
  double t;
  uint64_t *i = reinterpret_cast<uint64_t*>(&t);
  uint64_t one = 1;
  *i = ((one << 51) | (one << 62));
  std::cout << sizeof(uint64_t) << " " <<  sizeof(uint64_t*) << " "
            << sizeof(double) << " " <<  sizeof(double*) << std::endl;
  std::cout << t << std::endl;
  return 0;
}

這個的輸出是

8 8 8 8
3

用g ++ 4.3編譯時沒有優化。 但是,如果我添加-O2或-O3優化標志,我會得到一個奇怪的行為。 也就是說,如果我只是按原樣離開主,我得到相同的輸出。 但是如果我刪除輸出4 sizeof的行,那么我得到的輸出

0

沒有sizeof輸出的未優化版本也會正確返回3。

所以我想知道這是否是優化器的錯誤,或者我在這里做錯了什么。

是的,您違反了該語言的別名規則。 不允許通過指向另一種類型的指針寫入一種類型的對象( char*有一些例外)。

由於您從未寫入代碼中的任何double ,因此允許編譯器假定t永遠不會賦值。 (並輸出錯誤本身:-)

GCC有一個擴展,允許你寫一個類型的值,並將它作為另一種類型讀取,如果你把它們都放在一個聯合中。 這是編譯器特定的(但是半便攜式,因為其他人必須遵循領先)。

從技術上講,你有未定義的行為,雖然顯然是標准的意圖,這在明顯的情況下起作用,如果可以看到reinterpret_cast ,那么打破它的編譯器是不正常的。 如果您知道平台的字節順序,則可以通過使用uint8_t (字符類型)來操作位,或者將memcpy存入uint64_t ,然后將結果memcpy返回到double

如果你使用union g ++將使這個工作。 在所有訪問都通過union類型的情況下。 然而,該標准明確禁止這一點(盡管它是標准前幾天的首選解決方案),而且我使用的編譯器不起作用。

使用g ++,還有一個選項-fnostrict-aliasing ,它可以使它工作。

嘗試:

int main()
{
      volatile double    t;
  //  ^^^^^^^^ Tells the compiler this may be modified unexpectedly.

      volatile uint64_t& i   = reinterpret_cast<volatile uint64_t&>(t);
      uint64_t           one = 1;

      i = ((one << 51) | (one << 62));
      std::cout << t << std::endl;
}

暫無
暫無

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

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