我有一个使用位域来优化内存的结构。我有一个uint64_t
类型,我想打印它的值。编译后会显示以下警告:format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 5 has type ‘long unsigned int:48’ [-Wformat=]
我已经尝试通过在编译-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));
}
答案 0 :(得分:2)
首先,对uint64_t
和size_t
类型使用正确的格式说明符,并使用PRIu64
和inttypes.h
中定义的%zu
宏。
也就是说,对于位字段变量,
(uint64_t)self->mid
,或者您可以使用类型uint64_t
的中间变量,将成员变量值分配给新的中间变量,然后将其作为格式说明符的对应参数传递给printf()
,喜欢
uint64_t temp = self->mid;
printf("%"PRIu64 "\n", temp);
答案 1 :(得分:2)
尽管您当然应该在其他答案中应用这些修补程序以获取可移植格式说明符,但该警告将持续存在。原因是像printf
这样的可变参数的额外参数会经历参数提升。参数提升包括整数提升。
整数提升规则会将所有转换等级小于int
/ unsigned
的整数以及位字段转换为int
/ {{1} }。因此,对于您的初始位域,您会自动获得unsigned
。
对于具有高于int
/ int
的转换排名的整数,不进行提升。因此,您的位字段不会提升为unsigned
,并且您会收到有关参数不匹配的警告。您需要演员表。
uint64_t
顺便说一句,由于没有人提及,(uint64_t)self->mid
(size_t
运算符的类型)的可移植格式说明符是sizeof
。您应该使用它而不是%zu
。
答案 2 :(得分:0)
printf
之类的功能正在由编译器(并非全部)检查。编译器检查格式说明符是否与传递的参数类型匹配。您需要进行显式转换,以使Warning
消失。如其他答案所述,有一些隐式整数提升规则,您需要了解它们(感谢@storyTeller)。
整数提升规则会将转换等级小于int / unsigned以及位字段的任何整数转换为int / unsigned。因此,对于您的初始位字段,您将自动获得unsigned int。
对于具有高于int / unsigned的转换等级的整数,不进行提升。因此,您的位字段不会提升为uint64_t,并且您会收到有关参数不匹配的警告。您需要演员表。
尝试一下:
(uint64_t)self->mid
我已经尝试通过在编译-Wno格式时进行键入来抑制此警告。我想知道是否有更好的方法。
抑制警告不是一个好主意。它们的产生是有原因的。我建议使用警告标记,例如-Wall
,-Wshadow
,-Wextra
和其他重要标记。他们可以帮助您以更少的bug数量部署代码。
关于您的假设:
我有一个使用位域来优化内存的结构。
我想指出的是,您使用位域的结构不会像您考虑的那样优化内存。有一种叫做Padding
和Data Alignment
的东西可以帮助您进一步减少内存占用。
选中此question。