是否有更好的方法来缓解此警告?

问题描述 投票:3回答:3

我有一个结构,我使用位域来优化内存。我有一个uint64_t类型,我想打印它的价值。编译时,它向我显示了这个警告:format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 5 has type ‘long unsigned int:48’ [-Wformat=]

我已经尝试通过在编译qazxsw poi时键入来禁止此警告。我想知道是否有更好的方法来做到这一点。

这里有一些代码:

-Wno-format
c printf warnings bit-fields gcc-warning
3个回答
2
投票

虽然您应该在其他答案中应用修复程序来获取可移植格式说明符,但警告仍将存在。原因是像#include <stdint.h> #include <stdio.h> typedef struct gn_addr { unsigned int m:1; unsigned int st:5; unsigned int reserved:10; uint64_t mid:48; } gn_addr ; void gn_addr__print(gn_addr *self) { printf("M=>%d\nST=>%d\nReserved=>%d\nMID=>%lu\nTotal size %ld bytes\n", self->m, self->st, self->reserved, self->mid, sizeof(self)); } 这样的可变函数的额外参数经历了参数提升。参数促销包括整数提升。

整数提升的规则将转换等级小于printf / int的任何整数以及位字段转换为unsigned / int。因此,对于您的初始位域,您会自动获得unsigned

对于转换率高于int / int的整数,不会发生促销。因此,您的位字段不会提升为unsigned,并且您会收到有关参数不匹配的警告。你需要一个演员。

uint64_t

顺便说一句,因为没有人提到过,(uint64_t)self->mid size_t运算符的类型)的可移植格式说明符是sizeof。你应该使用它而不是%zu


2
投票

首先,对%lduint64_t类型使用正确的格式说明符,使用size_t宏定义的PRIu64宏,inttypes.h%zu

也就是说,对于位域变量,

  • 你可以使用演员,比如(uint64_t)self->mid
  • 或者您可以使用uint64_t类型的中间变量,将成员变量值分配给新的中间变量,并将其作为格式说明符的对应参数传递给printf(),如 uint64_t temp = self->mid; printf("%"PRIu64 "\n", temp);

0
投票

printf等函数正在由编译器(并非所有)进行检查。编译器检查格式说明符是否与传递的参数类型匹配。您需要进行显式转换才能使Warning消失。正如在其他答案中提到的那样,有一些隐含的整数提升规则,你需要知道它们(感谢@storyTeller)。

整数提升的规则将转换等级小于int / unsigned的任何整数以及位字段转换为int / unsigned。因此,对于初始位字段,您将自动获得unsigned int。

对于转换级别高于int / unsigned的整数,不会进行升级。因此,您的位字段不会提升为uint64_t,并且您会收到有关参数不匹配的警告。你需要一个演员。

试试这个:

(uint64_t)self->mid

我已经尝试通过在编译-Wno-format时键入来抑制此警告。我想知道是否有更好的方法来做到这一点。

抑制警告并不是一个好主意。它们是有原因产生的。我建议使用像-Wall-Wshadow-Wextra和其他重要标志的警告标志。他们可以帮助您部署具有较少数量的错误的代码。

关于你的假设:

我有一个结构,我使用位域来优化内存。

我想指出你的位域结构不会像你考虑的那样对内存进行优化。有一种叫做PaddingData Alignment的东西可以帮助你进一步减少内存占用。

检查这个question

© www.soinside.com 2019 - 2024. All rights reserved.