[英]Access struct variable value by pointer offset
我有一个看起来像的结构:
#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
请问你能帮帮我吗?
您的代码有很多问题,我将尝试全部解决:
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在编译期间修改编译器的行为而使用不同的打包和填充时,会发生这种情况。
最后,我确定根本不需要使用指针枚举结构成员。
我鼓励您阅读有关struct padding和packing的文章,好的起点是SO上的以下问题: Structure padding和packing
可以肯定的是,您将无法手动编写这些偏移量。 这绝对不是一种稳定的操作方式,因为编译器可能会进行优化,例如对齐struct成员 。
您可以执行以下操作:
Wheather_Struct w;
long offsetsOfStructAttributes[3] = {0,
(char*)&w.packetSize - (char*)&w.packetID,
(char*)&w.cloudLayerAltitude - (char*)&w.packetID};
请注意,这是字节大小的差异。
告诉您如何操作后,我必须像人们在评论中说的那样说,请找到另一种方式。 这是不安全的,除非您完全知道自己在做什么。
您的方法存在两个问题:
首先,它要求您正确选择尺寸。 使用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()
返回以字节为单位的大小,这不太可能是元素计数。
最后,您的变量有错别字:气象与天气是否好有关。 您已经混淆了这两个词,我很确定您的意思是“天气”。
您的错误是您假设该类在成员之间没有填充。 但是必须有填充,才能满足成员的对齐要求。 因此,偏移量不是您所假定的。
要获取类成员的偏移量, 可以使用标准库提供的offsetof
宏。 就是说,在不知道您需要什么的情况下,我仍然怀疑它是否合适。 请注意, offsetof
仅在您的类是标准布局类时才有效。 否则,行为将是不确定的。 您的示例WHEATHER_STRUCT
是标准布局。
cout << &pointer << ' ';
这样的事情可能无法获得您期望的输出。 您使用指针的地址,它可能无法为您提供所需的指向对象的值。
获得指示值的方法是间接运算符。 但是,仅当指针的类型正确时,间接操作符才能正确工作(对于float成员, float*
,对于uint16_t成员, uint16_t*
...),但是由于它必须是指向字节的指针,因此它不能为正确的类型。使用偏移量的指针算法。
除了偏移量,还需要了解变量的类型才能解释该值。 您可以将类型存储在某种结构中。 但是你可以将指针不投在运行时确定的类型,所以你需要的是一些运行时流结构,如switch
或跳转表的转换。
您最好不要使用指针黑客:有一天底层的内存布局将被更改,您的程序可能会破坏它。 尝试模拟元数据。
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 << " ";
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.