我有一个看起来像这样的结构
#pragma pack(1)
typedef struct WHEATHER_STRUCT {
uint8_t packetID; // Value 9
uint16_t packetSize; // Value 7
float cloudLayerAltitude; // Value 25000
} Wheather_Struct
此结构已正确初始化。由于算法的设计,我需要通过指针偏移量来读取这三个属性值。我感谢声明一个数组,这些数组的大小以字节为单位。就像:
int sizeOfStructAttributes = {1, 2, 4};
最后要访问这些值,请执行以下操作:
pointer = (*this->wheather_struct->packetID)
for (i=0; i<sizeof(sizeOfStructAttributes); i++)
cout << &pointer << ' ';
pointer = pointer + sizeOfStructAttributes[i];
预期结果:
9 7 25000
能帮我吗?
答案 0 :(得分:2)
您的代码有很多问题,我将尝试全部解决:
1-您的结构的填充值取决于您要定位的体系结构,可能在第一个成员(packetID)之后3或7个字节,取决于结构和编译器。
2-您以错误的方式初始化了指针,应该是:
pointer = &(this->wheather_struct->packetID);
3- cout应该是:
cout << *((datatype*)pointer) << ' ';
//datatype should be different in each loop iteration of course.
4-如果要创建此结构的数组,则不确定是否会遇到填充问题。在极少数情况下,由于将代码与其他使用不同编译器指令编译的库混合甚至使用#pragma在编译期间修改编译器的行为而使用不同的打包和填充时,就会发生这种情况。
最后,我确定根本不需要使用指针枚举结构成员。
我鼓励您阅读有关结构填充和打包的信息,开始的好地方是SO上的以下问题: Structure padding and packing
答案 1 :(得分:0)
可以肯定的是,您将无法手动编写这些偏移量。这绝对不是一种稳定的工作方式,因为您的编译器可能会进行诸如aligning your struct members之类的优化。
您可以执行以下操作:
Wheather_Struct w;
long offsetsOfStructAttributes[3] = {0,
(char*)&w.packetSize - (char*)&w.packetID,
(char*)&w.cloudLayerAltitude - (char*)&w.packetID};
请注意,这是字节大小的差异。
已经告诉您如何做到这一点,我必须像人们在评论中说的那样说,请找到另一种方式。这是不安全的,除非您完全知道自己在做什么。
答案 2 :(得分:0)
您的方法有两个问题:
首先,它要求您正确设置尺寸。使用sizeof
来做到这一点。所以你的数组看起来像:
size_t sizeOfStructAttributes = {sizeof(wheather_struct::packet_id),
sizeof(wheather_struct::packet_size),
sizeof(wheather_struct::cloudLayerAltitude) };
第二个(更严重的)问题是您不允许在结构中填充。几乎所有的编译器都将(除非特别指示)在packet_id和packet_size之间插入一个填充字节,以便所有内容都能很好地对齐。幸运的是,也有一个解决方案-使用offsetof
宏(在stddef.h中定义):
size_t offsetOfStructAttributes = {offsetof(wheather_struct, packet_id),
offsetof(wheather_struct, packet_size),
offsetof(wheather_struct, cloudLayerAltitude) };
然后代码变为:
for (size_t offset: offsetsOfStructAttributes) {
pointer = &(this->wheather_struct->packetID) + offset
cout << pointer << ' ';
}
实际上:上面的代码解决了您的代码的第三个问题:sizeof()
返回以字节为单位的大小,这不太可能是元素计数。
最后,您的变量有错别字:气象与天气是否好有关。您已经混淆了这两个词,我很确定您的意思是“天气”。
答案 3 :(得分:0)
您的错误是您假设类在成员之间没有填充。但是必须有填充,才能满足成员的对齐要求。因此,偏移量不是您所假设的。
要获取类成员的偏移量,您可以 使用标准库提供的offsetof
宏。就是说,在不知道您需要什么的情况下,我仍然怀疑它是否合适。请注意,offsetof
仅在您的类是标准布局类时才有效。否则,行为将是不确定的。您的示例WHEATHER_STRUCT
是标准布局。
cout << &pointer << ' ';
类似这样的可能无法获得您期望的输出。您使用指针的地址,它可能无法为您提供所需的指向对象的值。
获得指示值的方法是间接运算符。但是,仅当指针的类型正确(对于float成员,float*
,对于uint16_t成员,uint16_t*
)时,间接操作符才能正确工作,但由于必须为a指向字节的指针,以便指针算术可以使用偏移量。
除了偏移量,还需要了解变量的类型才能解释该值。您可以将类型存储在某种结构中。但是您不能将指针强制转换为在运行时确定的类型,因此您需要的是一些运行时流程结构,例如switch
或用于转换的跳转表。
答案 4 :(得分:0)
您最好不要使用指针黑客:有一天底层的内存布局将被更改,您的程序可能会破坏它。 尝试模拟元数据。
enum WheatherStructFields
{
wsfPacketID,
wsfPacketSize,
wsfCloudLayerAltitude,
wsfNone
};
typedef struct WHEATHER_STRUCT
{
uint8_t packetID;
uint16_t packetSize;
float cloudLayerAltitude;
void OutFieldValue(std::ostream& os, WheatherStructFields whatField)
{
switch (whatField)
{
case wsfPacketID:
os << (int)packetID;
break;
case wsfPacketSize:
os << packetSize;
break;
case wsfCloudLayerAltitude:
os << cloudLayerAltitude;
break;
default:
os << "Unsupported field: " << whatField;
}
}
} Wheather_Struct;
int main()
{
Wheather_Struct weather = { 9, 7, 25000 };
for (WheatherStructFields whatField = wsfPacketID; whatField < wsfNone;
whatField = (WheatherStructFields)((int)whatField + 1))
{
weather.OutFieldValue(std::cout, whatField);
std::cout << " ";
}
}