2016-10-05 19 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

相关问题