2016-10-05 18 views
4

考慮下面的代碼。如何安全地將更寬的整數類型轉換爲位域?

#include <stdint.h> 

struct MaskAndCount{ 
    uint64_t occupied : 56; 
    uint8_t numOccupied : 8; 
}; 

int main(){ 
    int count = 7; 
    MaskAndCount foo; 
    foo.occupied &= ~(1L << count); 
} 

如果我編譯此代碼與-Wconversion,那麼我會得到以下錯誤。

g++ -Wconversion Main.cc 
Main.cc: In function ‘int main()’: 
Main.cc:11:18: warning: conversion to ‘long unsigned int:56’ from ‘long unsigned int’ may alter its value [-Wconversion] 
    foo.occupied &= ~(1L << count); 

這似乎是一個合理的問題,但我期望的行爲恰恰是截斷右側值的所有高位。

我的問題是雙重的。

  1. 寫入的轉換是否具有所需的截斷右側值的高位的效果?
  2. 是否有辦法在本地使警報靜音或用不會觸發警告的不同語法表達相同的行爲?

請注意,我已經嘗試了下面的靜態轉換,它根本不能編譯。

static_cast<uint64_t:56>(~(1L << count)) 
+0

您唯一的選擇可能是關閉該特定警告。如果你想知道你需要如何指定你的編譯器。 –

+0

@MarkRansom,不幸的是,這個語句出現在頭文件的模板化函數中,而且我正在編寫一個庫,所以我必須要求我的庫的每個用戶也關閉警告,這似乎可能會減少一套願意嘗試我的圖書館的應用程序。 – merlin2011

回答

3

正如最高位(如果設置)將被忽略。

您可以通過轉讓自己之前去除頂部位避免了警告:

int count = 7; 
MaskAndCount foo = {}; 
           // chop off the top 8 bits 
foo.occupied &= ~(1 << count) & 0x00FFFFFFFFFFFFFFUL; 

編輯:原來這不會爲|=工作(不知道爲什麼)。但可以通過避免|=並使用正常分配來修復:

foo.occupied = (foo.occupied & ~(1UL << count)) & 0x00FFFFFFFFFFFFFFUL; 
foo.occupied = (foo.occupied | ~(1UL << count)) & 0x00FFFFFFFFFFFFFFUL; 
+0

你不需要在那個常量的末尾加一個'L'嗎? –

+0

@MarkRansom TBH我不確定。常數太長而不能成爲'long',所以我認爲編譯器會計算出來,但我會把它放進去,因爲你可能是對的。 – Galik

+0

不幸的是,在使用'|'而不是'&='的情況下,這不起作用,但我已經問了一個[新問題](http://stackoverflow.com/q/39882045/391161)以避免混淆。 – merlin2011

相關問題