如何在C语言中创建24位无符号整数
我正在开发一个内存非常紧张的嵌入式应用程序。 为此,我需要创建一个24位无符号整数数据类型。我使用的是结构:如何在C语言中创建24位无符号整数,c,struct,printf,typedef,C,Struct,Printf,Typedef,我正在开发一个内存非常紧张的嵌入式应用程序。 为此,我需要创建一个24位无符号整数数据类型。我使用的是结构: typedef struct { uint32_t v : 24; } uint24_t; 但是,当我询问此类型变量的大小时,它返回“4”,即: 有没有办法强制这个变量有3个字节 起初我认为这是因为它强制数据类型与单词对齐,但我可以这样做: typedef struct { uint8_t blah[3]; } mytype; 在这种情况下,尺寸为3 好吧,你可以尝试
typedef struct
{
uint32_t v : 24;
} uint24_t;
但是,当我询问此类型变量的大小时,它返回“4”,即:
有没有办法强制这个变量有3个字节
起初我认为这是因为它强制数据类型与单词对齐,但我可以这样做:
typedef struct
{
uint8_t blah[3];
} mytype;
在这种情况下,尺寸为3 好吧,你可以尝试确保结构只占用你需要的空间,比如:
#pragma pack(push, 1)
typedef struct { uint8_t byt[3]; } UInt24;
#pragma pack(pop)
// Inline suggestion used to (hopefully) reduce overhead.
inline uint32_t unpack(UInt24 x) {
uint32_t retVal = x.byt[0];
retval = retVal << 8 | x.byt[1];
retval = retVal << 8 | x.byt[2];
return retVal;
}
inline UInt24 pack(uint32_t x) {
UInt24 retVal;
retVal.byt[0] = (x >> 16) & 0xff;
retVal.byt[1] = (x >> 8) & 0xff;
retVal.byt[2] = x & 0xff;
return retVal
}
您可能必须提供这些编译器指令(如上面的#pragma
行)以确保没有填充,但这可能是只有八位字段(a)的结构的默认设置
然后,您可能需要将实际值打包/解包到结构中,或从结构中打包/解包,例如:
#pragma pack(push, 1)
typedef struct { uint8_t byt[3]; } UInt24;
#pragma pack(pop)
// Inline suggestion used to (hopefully) reduce overhead.
inline uint32_t unpack(UInt24 x) {
uint32_t retVal = x.byt[0];
retval = retVal << 8 | x.byt[1];
retval = retVal << 8 | x.byt[2];
return retVal;
}
inline UInt24 pack(uint32_t x) {
UInt24 retVal;
retVal.byt[0] = (x >> 16) & 0xff;
retVal.byt[1] = (x >> 8) & 0xff;
retVal.byt[2] = x & 0xff;
return retVal
}
不过,这只是一个示例,因此,您可能需要考虑到“便携代码”,使用诸如“<代码> >”PrimaMaPa(1)之类的代码,或者放入代码来捕获可能并非如此的环境。
< P>,您可以尝试确保该结构只占用您所需的空间,例如:#pragma pack(push, 1)
typedef struct { uint8_t byt[3]; } UInt24;
#pragma pack(pop)
// Inline suggestion used to (hopefully) reduce overhead.
inline uint32_t unpack(UInt24 x) {
uint32_t retVal = x.byt[0];
retval = retVal << 8 | x.byt[1];
retval = retVal << 8 | x.byt[2];
return retVal;
}
inline UInt24 pack(uint32_t x) {
UInt24 retVal;
retVal.byt[0] = (x >> 16) & 0xff;
retVal.byt[1] = (x >> 8) & 0xff;
retVal.byt[2] = x & 0xff;
return retVal
}
您可能必须提供这些编译器指令(如上面的#pragma
行)以确保没有填充,但这可能是只有八位字段(a)的结构的默认设置
然后,您可能需要将实际值打包/解包到结构中,或从结构中打包/解包,例如:
#pragma pack(push, 1)
typedef struct { uint8_t byt[3]; } UInt24;
#pragma pack(pop)
// Inline suggestion used to (hopefully) reduce overhead.
inline uint32_t unpack(UInt24 x) {
uint32_t retVal = x.byt[0];
retval = retVal << 8 | x.byt[1];
retval = retVal << 8 | x.byt[2];
return retVal;
}
inline UInt24 pack(uint32_t x) {
UInt24 retVal;
retVal.byt[0] = (x >> 16) & 0xff;
retVal.byt[1] = (x >> 8) & 0xff;
retVal.byt[2] = x & 0xff;
return retVal
}
不过,这只是一个示例,因此,您可能需要考虑到“便携代码”,使用诸如“<代码> >”PraceMaPa包(1)之类的代码,或者放入代码来捕获可能不是这种情况的环境。
< P> ON说,您可以使用<代码>另一个选项是使用\uuuuuuuuuuuuuu属性((打包))
:
这应该适用于GCC和Clang
但是,请注意,这可能会破坏对齐,除非您的处理器支持未对齐的访问。上说您可以使用\pragma pack
。另一个选项是使用\uuuuuuuuuuuuuu属性((打包))
:
这应该适用于GCC和Clang
但是,请注意,这可能会破坏对齐,除非您的处理器支持未对齐的访问
起初我认为这是因为它迫使数据类型与单词对齐
不同的数据类型可以有不同的对齐方式。例如,参见文档
您可以使用alignof
进行检查,但是char
或uint8\u t
具有1字节对齐(即,实际上没有)是完全正常的,但是uint32\u t
具有4字节对齐。我不知道是否明确描述了位字段的对齐方式,但从存储类型继承它似乎足够合理
注意。具有对齐要求的原因通常是,它与底层硬件配合得更好。如果您确实使用了#pragma pack
或uuuu属性((packed))
或其他任何东西,那么编译器或内存硬件会以静默方式处理未对齐的访问,这可能会影响性能
在我看来,仅仅显式存储一个3字节数组可能更好
起初我认为这是因为它迫使数据类型与单词对齐
不同的数据类型可以有不同的对齐方式。例如,参见文档
您可以使用alignof
进行检查,但是char
或uint8\u t
具有1字节对齐(即,实际上没有)是完全正常的,但是uint32\u t
具有4字节对齐。我不知道是否明确描述了位字段的对齐方式,但从存储类型继承它似乎足够合理
注意。具有对齐要求的原因通常是,它与底层硬件配合得更好。如果您确实使用了#pragma pack
或uuuu属性((packed))
或其他任何东西,那么编译器或内存硬件会以静默方式处理未对齐的访问,这可能会影响性能
我认为,只显式存储3字节数组可能更好。首先,不要使用位字段或结构。它们可以随意包含填充,位字段通常不可移植 除非您的CPU显式地得到24位算术指令(除非是某个古怪的DSP,否则这似乎不太可能),否则自定义数据类型只能实现额外的堆栈膨胀 最有可能的情况是,所有算术运算都必须使用
uint32\t
。这意味着您的24位类型在节省RAM方面可能没有多大成就。如果您发明了一些具有setter/getter(序列化/反序列化)访问权限的定制ADT,那么您可能只是在浪费RAM,因为如果函数不能内联,那么您将获得更高的堆栈峰值使用率
为了实际节省RAM,您应该修改您的程序设计
也就是说,您可以基于数组创建自定义类型:
typedef unsigned char u24_t[3];
每当您需要访问数据时,您可以memcpy
32位类型的数据,然后在32位上执行所有算术运算:
u24_t u24;
uint32_t u32;
...
memcpy(&u32, u24, sizeof(u24));
...
memcpy(&u24, &u32, sizeof(u24));
但请注意,这假设的是小端,因为我们只处理位0到2。对于大端系统,您必须执行
memcpy((uint8_t*)和u32+1,
以丢弃MS字节。首先,不要使用位字段或结构。它们可以随意包含填充,并且位字段通常不可移植
除非您的CPU显式地得到24位算术指令(除非是某个古怪的DSP,否则这似乎不太可能),否则自定义数据类型只能实现额外的堆栈膨胀
最有可能的情况是,您必须对所有算术使用uint32\u t
。这意味着您的24位类型在节省RAM方面可能没有多大成就。如果您发明了一些带有setter/ge的自定义ADT