我有一个结构,我使用位域来优化内存。我有一个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
虽然您应该在其他答案中应用修复程序来获取可移植格式说明符,但警告仍将存在。原因是像#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
。
首先,对%ld
和uint64_t
类型使用正确的格式说明符,使用size_t
宏定义的PRIu64
宏,inttypes.h
和%zu
。
也就是说,对于位域变量,
(uint64_t)self->mid
uint64_t
类型的中间变量,将成员变量值分配给新的中间变量,并将其作为格式说明符的对应参数传递给printf()
,如
uint64_t temp = self->mid;
printf("%"PRIu64 "\n", temp);
printf
等函数正在由编译器(并非所有)进行检查。编译器检查格式说明符是否与传递的参数类型匹配。您需要进行显式转换才能使Warning
消失。正如在其他答案中提到的那样,有一些隐含的整数提升规则,你需要知道它们(感谢@storyTeller)。
整数提升的规则将转换等级小于int / unsigned的任何整数以及位字段转换为int / unsigned。因此,对于初始位字段,您将自动获得unsigned int。
对于转换级别高于int / unsigned的整数,不会进行升级。因此,您的位字段不会提升为uint64_t,并且您会收到有关参数不匹配的警告。你需要一个演员。
试试这个:
(uint64_t)self->mid
我已经尝试通过在编译-Wno-format时键入来抑制此警告。我想知道是否有更好的方法来做到这一点。
抑制警告并不是一个好主意。它们是有原因产生的。我建议使用像-Wall
,-Wshadow
,-Wextra
和其他重要标志的警告标志。他们可以帮助您部署具有较少数量的错误的代码。
关于你的假设:
我有一个结构,我使用位域来优化内存。
我想指出你的位域结构不会像你考虑的那样对内存进行优化。有一种叫做Padding
和Data Alignment
的东西可以帮助你进一步减少内存占用。
检查这个question。