2014-04-04 47 views
0

我有以下代码。警告:整型常量对于“long”类型来说太大

uint32_t reg_val = 0; 
    uint64_t val = 0; 
    reg_val = 0; 
    reg_val = ((val & 0xffffff000000) >> 24); 
    dev_write(rw,reg_val); 

编译器给出了说

warning: integer constant is too large for "long" type 

我只分配24位reg_val这是定义为大小32位的无符号整数警告。

为什么编译器会生成此警告?

+4

屏蔽掉低位24位的目的是什么?右对齐右值之前的位置,使得低位24位被删除?在我看来,它是没有真正目的的冗余代码。 – enhzflep

+1

它可以避免在* upper *位有任何东西,我想。 – greggo

+0

我隐约回忆起你需要在文字上附加“LL”来让编译器感到高兴。 –

回答

8

常量0xffffff000000对于32位长度来说太大,对于您的情况,其范围为0x7fffffff

把它写成0xFFFFFF000000ULLunsigned long long) 或回避的问题写

reg_val = (val >> 24) & 0xFFFFFF; 
1

上greggo的优良答案扩展了一下。

如何字面的整数被定义取决于我们在哪种语言的版本。

在C99,整数常量自动具有可以包含其值(除非没有这种类型存在)一个类型。所以,假设32位long,那么这个常量已经有unsigned long long类型,所以不应该发生警告。

我没有C89文本的副本,但C89没有long long。如果规则类似,那么会发生什么情况是常量会以实现定义的方式(可能会截断更高位)转换为32位unsigned long

由于OP得到警告,但也能用ull后缀解决它,这表明他正在使用编译器扩展。理论上,如果编译器以类似C89的模式提供long long,则其应该也更新其整数字面值规则,以便不适合long的文字具有类型long long(可能是无符号的)。

但是,我听说编译器存在不这样做;他们截断了文字,而不是给它一个适合的类型,除非你把自己的后缀。

tl; dr - 后缀不应该是必需的;但它永远不会使用它,它可以解决糟糕的编译器扩展。

+0

或者他们会将其推广到适合的类型,但是会带来警告,如果您将代码移动到其他编译器之一,则很有必要。整个“自动类型”方法的一个问题:如果您有0xFFFF0000,它可以根据是以uint32还是以int64完成的结果做出很大的改变。 – greggo

+0

假设我的表达式是'(intvar1 + Literal_Const)* intvar2 >> 8',并且Literal_const是0x7FFF8000或0xFFFF0000或0x1FFFE0000;所以被认为是int32,uint32或int64。这是一条相当颠簸的道路。显式类型在这种情况下是必不可少的。 – greggo

+0

根据C99,0xFFFF0000必须是无符号的(我认为C89也是这样,AFAIK规则在这两个版本之间不会改变为'long long'以外的类型) - 较小宽度类型总是优于较大宽度类型,毛发十六进制和八进制常量(但不是十进制常量!) –