从另一个字节数组到双精度数组的别名

问题描述

我正在尝试从一个字节数组创建一个双精度数组的别名。但它的行为恰好与我预期的不同。 字节数组存储 - 传感器代码 (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

解决方法

我无法对您的帖子发表评论,因此我将添加另一个答案:D。 该版本有效,因为现在您正确地进行了转换。 mSensorData + sizeof(int32_t)) 现在将使您在 sizeof(int32_t) 的右侧获得 mSensorData 个字节(请注意,发生这种情况是因为 mSensorData 的类型为 byte ..它实际上将您带入 {{1} } 字节向右,但 sizeof(int32_t) * sizeof(std::byte) 的大小为 1)。

它以前不起作用,因为 std::bytes 是完全不同的东西。首先,(double (*)[3])&mSensorData + sizeof(int32_t) 与此无关。您将最终获得堆栈地址并开始转换堆栈上的内容。但即使那不存在,& 仍然是错误的。它的作用是将 (double (*)[3])mSensorData + sizeof(int32_t) 转换为 3 个双精度数组,然后将指针 mSensorData 向右移动。注意到区别了吗?现在你的指针是 sizeof(int32_t) * 3 * sizeof(double) 类型,所以它的任何算术都会移动你的指针 double (*)[3] 字节

,

抛开可怕的别名违规问题,以及您真的、真的不能这样做的事实:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-7ca687ee0af3> in <module>
     14 import pandas as pd
     15 
---> 16 rols = RollingOLS(X,y,window=60)
     17 rres = rols.fit()
     18 params = rres.params

/opt/conda/lib/python3.8/site-packages/statsmodels/regression/rolling.py in __init__(self,endog,exog,window,min_nobs,missing,expanding)
    445         expanding=False
    446     ):
--> 447         super().__init__(
    448             endog,449             exog,/opt/conda/lib/python3.8/site-packages/statsmodels/regression/rolling.py in __init__(self,weights,expanding)
    154         self.k_constant = k_const
    155         self.data.const_idx = const_idx
--> 156         self._y = array_like(endog,"endog")
    157         nobs = self._y.shape[0]
    158         self._x = array_like(exog,"endog",ndim=2,shape=(nobs,None))

/opt/conda/lib/python3.8/site-packages/statsmodels/tools/validation/validation.py in array_like(obj,name,dtype,ndim,maxdim,shape,order,contiguous,optional)
    145         if arr.ndim != ndim:
    146             msg = "{0} is required to have ndim {1} but has ndim {2}"
--> 147             raise ValueError(msg.format(name,arr.ndim))
    148     if shape is not None:
    149         for actual,req in zip(arr.shape,shape):

ValueError: endog is required to have ndim 1 but has ndim 2

您的目的是在 (double (*)[3])&mSensorData + sizeof(int32_t) 开始后为 sizeof(int32_t) 字节创建别名。

然而,这不是指针添加在 C++ 中的工作方式。毕竟,鉴于以下情况:

mSensorData

int *p; int *q=p+1; 是否指向 q 之后的 1 个字节。 p 指向 q 指向的位置之后的 next 整数。在 64 位平台上,p 指向 q 之后的 8 个字节。

实际上,当您向指针添加某些内容时,添加的任何内容(包括减法)都会乘以 p 的指针指向的内容。

因此,上述加法的结果是sizeof开头后的sizeof(int32_t)*sizeof(double (*)[3])字节的别名。

为了进行预期的计算,您需要先转换为 mSensorData,执行加法,然后转换为 char *

,

你在做什么似乎有点太复杂了。您只需要将其余的缓冲区从 char* 解释为您需要的类型。例如:

#include <iostream>
#include <cstring>

int main() {
    int size = sizeof(int32_t) + 3 * sizeof(double);
    char data[size];
    memset(data,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