来自另一个字节数组的双精度数组的别名
Alias to a double array from another byte array
我正在尝试从字节数组创建双精度数组的别名。但它的行为恰好与我预期的不同。
字节数组存储 - 传感器代码 (int) 后跟位置数据 (double[3])。这是我试过的
std::byte mSensorData[sizeof(int32_t) + 3 * sizeof(double)];
int32_t& mSensorCode = *((int32_t*) &mSensorData);
double (& mLocation)[3] = *((double (*)[3])&mSensorData + sizeof(int32_t));
/* some code, byte* gpsData contains location data */
memcpy(mLocation, gpsData, sizeof(mLocation));
DEBUG(std::cout<<mSensorCode <<std::endl;)
DEBUG(std::cout<<mLocation[0] <<std::endl;)
DEBUG(std::cout<<mLocation[1] <<std::endl;)
DEBUG(std::cout<<mLocation[2] <<std::endl;)
DEBUG(std::cout<<*((int*)&mSensorData[0]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[4]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[12]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[20]) <<std::endl;)
我得到的结果:
120
37.422
-122.084
16.6551
120
0
0
0
抛开可怕的混叠违规问题,以及你真的、真的不能这样做的事实:
(double (*)[3])&mSensorData + sizeof(int32_t)
您的目的是在 mSensorData
开始后为 sizeof(int32_t)
个字节创建一个别名。
但是,这不是 C++ 中指针加法的工作方式。毕竟,给出以下内容:
int *p;
int *q=p+1;
q
而不是 指向 p
之后的 1 个字节。 q
指向 next 整数 p
指向的位置。在 64 位平台上 q
指向 p
.
之后的 8 个字节
实际上,当您向指针添加内容时,添加的任何内容(包括减法)都会乘以指针指向的内容的 sizeof
。
因此,上述相加的结果是mSensorData
开始后sizeof(int32_t)*sizeof(double (*)[3])
字节的别名。
为了进行预期的计算,您需要先转换为 char *
,执行加法,然后转换为 double (*)[3]
。
你做的事情似乎有点太复杂了。您只需要将缓冲区的其余部分从 char*
解释为您需要的类型。例如:
#include <iostream>
#include <cstring>
int main() {
int size = sizeof(int32_t) + 3 * sizeof(double);
char data[size];
memset(data, 0, size);
data[0] = 1;
int first_int = *(int*)data;
double *doubles = (double*)(data + sizeof(int32_t));
printf("%d %f %f %f \n", first_int, doubles[0], doubles[1], doubles[2]);
}
对我来说效果很好。 1 0.000000 0.000000 0.000000
如果你愿意,你可以使用 reinterpret_cast 而不是 c 风格转换 double *doubles = reinterpret_cast<double *>(data + sizeof(int32_t));
,但你只是将缓冲区重新解释为双精度缓冲区而不是双精度缓冲区是一样的字符
知道为什么会这样吗?
gps.h
#ifndef GPS_H
#define GPS_H
#include <cstddef>
#include <stdint.h>
class GPS
{
std::byte mSensorData[sizeof(int32_t) + 3 * sizeof(double)];
int32_t& mSensorCode = *((int32_t*) mSensorData);
double (& mLocation)[3] = *((double (*)[3])(mSensorData + sizeof(int32_t)));
public:
GPS();
int processData(const std::byte* gpsData);
int getLocationData(std::byte* buffer) const;
};
#endif
gps.cpp
#include "gps.h"
#include "common.h"
#include <cstring>
#include <exception>
GPS::GPS(){
mSensorCode = LOCATION;
}
int GPS::processData(const std::byte* gpsData){
try {
gpsData += sizeof(int32_t);
memcpy(mLocation, gpsData, sizeof(mLocation));
DEBUG(std::cout<<"Buffer Content" <<std::endl;)
DEBUG(std::cout<<*((int*)&mSensorData[0]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[4]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[12]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[20]) <<std::endl;)
DEBUG(std::cout<<"Data Content" <<std::endl;)
DEBUG(std::cout<<mSensorCode <<std::endl;)
DEBUG(std::cout<<mLocation[0] <<std::endl;)
DEBUG(std::cout<<mLocation[1] <<std::endl;)
DEBUG(std::cout<<mLocation[2] <<std::endl;)
}catch(std::exception& ex) {
DEBUG(std::cout << "GPS::processData ex:" << ex.what() << std::endl;)
}
return sizeof(mSensorData);
}
int GPS::getLocationData(std::byte* buffer) const{
memcpy(buffer, &mSensorData, sizeof(mSensorData));
return sizeof(mSensorData);
}
结果
Buffer Content
120
37.422
-122.084
0.0962061
Data Content
120
37.422
-122.084
0.0962061
我不能评论你的 post 所以我会添加另一个答案 :D。
该版本有效,因为现在您正在正确进行转换。
mSensorData + sizeof(int32_t))
现在会让你在 mSensorData
右边得到 sizeof(int32_t)
字节(注意发生这种情况是因为 mSensorData
是 byte 类型..它实际上带你 sizeof(int32_t) * sizeof(std::byte)
字节向右,但 std::bytes
的大小为 1).
它以前没有用,因为 (double (*)[3])&mSensorData + sizeof(int32_t)
完全不同。首先, &
与那里无关。你最终会得到一个堆栈地址并开始转换堆栈上的东西。但即使那不存在,(double (*)[3])mSensorData + sizeof(int32_t)
仍然是错误的。它的作用是将 mSensorData
转换为 3 个双精度数组,然后将指针 sizeof(int32_t) * 3 * sizeof(double)
向右移动。注意到区别了吗?现在你的指针是 double (*)[3]
类型所以任何算术都会移动你的指针 3 * sizeof(double)
bytes
我正在尝试从字节数组创建双精度数组的别名。但它的行为恰好与我预期的不同。 字节数组存储 - 传感器代码 (int) 后跟位置数据 (double[3])。这是我试过的
std::byte mSensorData[sizeof(int32_t) + 3 * sizeof(double)];
int32_t& mSensorCode = *((int32_t*) &mSensorData);
double (& mLocation)[3] = *((double (*)[3])&mSensorData + sizeof(int32_t));
/* some code, byte* gpsData contains location data */
memcpy(mLocation, gpsData, sizeof(mLocation));
DEBUG(std::cout<<mSensorCode <<std::endl;)
DEBUG(std::cout<<mLocation[0] <<std::endl;)
DEBUG(std::cout<<mLocation[1] <<std::endl;)
DEBUG(std::cout<<mLocation[2] <<std::endl;)
DEBUG(std::cout<<*((int*)&mSensorData[0]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[4]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[12]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[20]) <<std::endl;)
我得到的结果:
120
37.422
-122.084
16.6551
120
0
0
0
抛开可怕的混叠违规问题,以及你真的、真的不能这样做的事实:
(double (*)[3])&mSensorData + sizeof(int32_t)
您的目的是在 mSensorData
开始后为 sizeof(int32_t)
个字节创建一个别名。
但是,这不是 C++ 中指针加法的工作方式。毕竟,给出以下内容:
int *p;
int *q=p+1;
q
而不是 指向 p
之后的 1 个字节。 q
指向 next 整数 p
指向的位置。在 64 位平台上 q
指向 p
.
实际上,当您向指针添加内容时,添加的任何内容(包括减法)都会乘以指针指向的内容的 sizeof
。
因此,上述相加的结果是mSensorData
开始后sizeof(int32_t)*sizeof(double (*)[3])
字节的别名。
为了进行预期的计算,您需要先转换为 char *
,执行加法,然后转换为 double (*)[3]
。
你做的事情似乎有点太复杂了。您只需要将缓冲区的其余部分从 char*
解释为您需要的类型。例如:
#include <iostream>
#include <cstring>
int main() {
int size = sizeof(int32_t) + 3 * sizeof(double);
char data[size];
memset(data, 0, size);
data[0] = 1;
int first_int = *(int*)data;
double *doubles = (double*)(data + sizeof(int32_t));
printf("%d %f %f %f \n", first_int, doubles[0], doubles[1], doubles[2]);
}
对我来说效果很好。 1 0.000000 0.000000 0.000000
如果你愿意,你可以使用 reinterpret_cast 而不是 c 风格转换 double *doubles = reinterpret_cast<double *>(data + sizeof(int32_t));
,但你只是将缓冲区重新解释为双精度缓冲区而不是双精度缓冲区是一样的字符
知道为什么会这样吗?
gps.h
#ifndef GPS_H
#define GPS_H
#include <cstddef>
#include <stdint.h>
class GPS
{
std::byte mSensorData[sizeof(int32_t) + 3 * sizeof(double)];
int32_t& mSensorCode = *((int32_t*) mSensorData);
double (& mLocation)[3] = *((double (*)[3])(mSensorData + sizeof(int32_t)));
public:
GPS();
int processData(const std::byte* gpsData);
int getLocationData(std::byte* buffer) const;
};
#endif
gps.cpp
#include "gps.h"
#include "common.h"
#include <cstring>
#include <exception>
GPS::GPS(){
mSensorCode = LOCATION;
}
int GPS::processData(const std::byte* gpsData){
try {
gpsData += sizeof(int32_t);
memcpy(mLocation, gpsData, sizeof(mLocation));
DEBUG(std::cout<<"Buffer Content" <<std::endl;)
DEBUG(std::cout<<*((int*)&mSensorData[0]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[4]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[12]) <<std::endl;)
DEBUG(std::cout<<*((double*)&mSensorData[20]) <<std::endl;)
DEBUG(std::cout<<"Data Content" <<std::endl;)
DEBUG(std::cout<<mSensorCode <<std::endl;)
DEBUG(std::cout<<mLocation[0] <<std::endl;)
DEBUG(std::cout<<mLocation[1] <<std::endl;)
DEBUG(std::cout<<mLocation[2] <<std::endl;)
}catch(std::exception& ex) {
DEBUG(std::cout << "GPS::processData ex:" << ex.what() << std::endl;)
}
return sizeof(mSensorData);
}
int GPS::getLocationData(std::byte* buffer) const{
memcpy(buffer, &mSensorData, sizeof(mSensorData));
return sizeof(mSensorData);
}
结果
Buffer Content
120
37.422
-122.084
0.0962061
Data Content
120
37.422
-122.084
0.0962061
我不能评论你的 post 所以我会添加另一个答案 :D。
该版本有效,因为现在您正在正确进行转换。
mSensorData + sizeof(int32_t))
现在会让你在 mSensorData
右边得到 sizeof(int32_t)
字节(注意发生这种情况是因为 mSensorData
是 byte 类型..它实际上带你 sizeof(int32_t) * sizeof(std::byte)
字节向右,但 std::bytes
的大小为 1).
它以前没有用,因为 (double (*)[3])&mSensorData + sizeof(int32_t)
完全不同。首先, &
与那里无关。你最终会得到一个堆栈地址并开始转换堆栈上的东西。但即使那不存在,(double (*)[3])mSensorData + sizeof(int32_t)
仍然是错误的。它的作用是将 mSensorData
转换为 3 个双精度数组,然后将指针 sizeof(int32_t) * 3 * sizeof(double)
向右移动。注意到区别了吗?现在你的指针是 double (*)[3]
类型所以任何算术都会移动你的指针 3 * sizeof(double)
bytes