带-Wsign-conversion的ANSI C全位集类型提升安全文本

mjqavswn  于 2023-03-22  发布在  其他
关注(0)|答案(3)|浏览(126)

我是否可以将任意宽度的无符号变量中的所有位都设置为1,而不会使用相同的文字触发符号转换错误(-Wsign-conversion)?
没有-Wsign-conversion,我可以:

#define ALL_BITS_SET (-1)
uint32_t mask_32 = ALL_BITS_SET;
uint64_t mask_64 = ALL_BITS_SET;
uintptr_t mask_ptr = ALL_BITS_SET << 12; // here's the narrow problem!

但是-W符号转换我被难倒了。

error: negative integer implicitly converted to unsigned type [-Werror=sign-conversion]

我尝试了(~0)和(~ 0 U),但没有骰子。预处理器将第一个提升为int,这会触发-Wsign转换,第二个不会提升超过32位,只设置64位变量的低32位。
我运气不好吗?
编辑:澄清一下,我在整个项目的许多地方都使用了定义的ALL_BITS_SET,所以我不愿意在源代码中添加(~(uint32_t)0)和(~(uintptr_t)0)之类的东西。

o2gm4chl

o2gm4chl1#

1的补码将所有的0变为1,反之亦然。
所以试试看

#define ALL_BITS_SET (~(0))
uint32_t mask_32 = ALL_BITS_SET;
uint64_t mask_64 = ALL_BITS_SET;
xzv2uavs

xzv2uavs2#

试试看

uint32_t  mask_32  = ~((uint32_t)0);
uint64_t  mask_64  = ~((uint64_t)0);
uintptr_t mask_ptr = ~((uintptr_t)0);

也许存在更清晰的解决方案-这一个有点迂腐,但相信它满足您的需求。

c9qzyr3d

c9qzyr3d3#

您收到警告“negative integer implicitly converted to unsigned type”的原因是0是一个文字整数值。作为文字整数值,它的类型为int,这是一个有符号类型,因此(~(0)),作为int类型的全位一值,的值为(int)-1。当然,将负值非隐式转换为无符号值的唯一方法是显式转换,但您似乎已经拒绝了使用适当类型转换的建议。替代选项:
显然,您也可以通过对无符号0 ... (~(0U))求反来消除到无符号类型的隐式转换,但这样您就只有unsigned int中的位数
编写一个稍微不同的宏,并使用宏来声明变量

`#define ALL_BITS_VAR(type,name) type name = ~(type)0`
`ALL_BITS_VAR(uint64_t,mask_32);`

但这仍然只适用于声明。
有人已经建议使用最广泛的可用类型定义ALL_BITS_SET,您拒绝了这个建议,理由是开发环境过于严格,但老实说,这是目前为止最好的方法。如果您的开发环境真的严格到禁止将无符号值赋值给较小类型的无符号变量,(其结果定义得非常清楚,而且完全有效),那么你就真的别无选择了,必须做一些特定于类型的事情:

#define ALL_BITS_ONE(type) (~(type)0)
uint32_t mask_32 = ALL_BITS_SET(uint32_t);
uint64_t mask_64 = ALL_BITS_SET(uint64_t);
uintptr_t mask_ptr = ALL_BITS_SET(uintptr_t) << 12;

就这样。
(实际上,这还不是全部……既然你说你正在使用GCC,你可以用GCC的typeof扩展做一些事情,但我仍然不知道如何在没有传递变量的函数宏的情况下使它工作。

相关问题