好的-因此,我将首先说我不确定如何描述这个问题以及我目前的困惑,以此作为开头。因此,我将尽力提供示例。

在memcpy调用中使用类型定义的定长数组的两种方法中的哪一种是正确的?还是等价的?
(我开始认为它们是等效的-在下面的“注释”下进行一些实验)。
语境
考虑以下typedef typedef uint8_t msgdata[150];和库接口(interface)const msgdata* IRead_GetMsgData (void);
在我的代码中,我使用IRead_GetMsgData并将结果memcpy存入另一个uint8_t缓冲区(下面的示例)。

//Included from library:
//typedef uint8_t msgdata[150];
//const msgdata* IRead_GetMsgData (void);

uint8_t mBuff[2048];
void Foo() {
    const msgdata* myData = IRead_GetMsgData();
    if(myData != nullptr) {
        std::memcpy(mBuff, *myData, sizeof(msgdata));
    }
}
现在,该方法可以正常工作并通过了单元测试,但在我们的团队之间开始了关于在这种情况下是否应取消引用myData的讨论。事实证明,不取消引用myData也是可行的,并通过了我们所有的单元测试
    std::memcpy(mBuff, myData, sizeof(msgdata)); //This works fine, too
编写memcpy调用时,我的想法是,因为myData的类型为msgdata *,对其取消引用将返回指向的msgdata,即uint8_t数组。
例如。
    typedef uint8 msgdata[150];
    msgdata mData = {0u};
    msgdata* pData = &mData;
    memcpy(somePtr, pData, size);  //Would expect this to fail - pData isn't the buffer mData.
    memcpy(somePtr, *pData, size); //Would expect this to work - dereferencing pData returns the buffer mData
    memcpy(somePtr, mData, size); //Would expect this to work - mData is the buffer, mData ==&mData[0]
我尝试过搜索类似问题的讨论,但还没有发现任何相关的内容:
  • Using new with fixed length array typedef-如何使用/格式化typedef
  • How to dereference typedef array pointer properly?-如何取消引用类型定义的数组并访问其元素
  • typedef fixed length array-再次格式化typedef。

  • 该列表中的最后一个与我最相关,因为公认的答案很好地说明了我(强调我的意思)

    现在,我试图理解实际发生的事情,但是我对此表示同意!尤其重要的是,它隐藏了您实际尝试使用的类型...
    笔记
    因此,在我们开始对此进行思考之后,我做了一些实验:
    typedef uint8_t msgdata[150];
    msgdata data = {0};
    msgdata* pData = &data;
    int main() {
        printf("%p\n", pData);
        printf("%p\n", *pData);
        printf("%p\n", &data);
        printf("%p\n", data);
    
        return 0;
    }
    Outputs:
    0x6020a0
    0x6020a0
    0x6020a0
    0x6020a0
    
    而且,如果我将其扩展为包括合适的数组arr和定义的大小值size,则可以使用各种memcpy调用,例如
        std::memcpy(arr, data, size);
        std::memcpy(arr, pData, size);
        std::memcpy(arr, *pData, size);
    
    它们的行为都一样,使我相信它们是等效的。
    我了解第一个和最后一个版本(data*pData),但是我仍然不确定pData版本正在发生什么...

    最佳答案

    IMO,此代码是完全错误的。我也将接受另一种观点,即“代码非常容易引起误解”

    //Included from library:
    //typedef uint8_t msgdata[150];
    //const msgdata* IRead_GetMsgData (void);
    
    uint8_t mBuff[2048];
    void Foo() {
        const msgdata* myData = IRead_GetMsgData();
        if(myData != nullptr) {
            std::memcpy(mBuff, *myData, sizeof(msgdata));
        }
    }
    
    取消引用*myData时,会误导读者。显然,memcpy需要一个指向msgdata的指针,因此不需要解引用星号。 myData已经是一个指针。引入额外的取消引用将破坏代码。
    但这不是...为什么?
    这就是您特定用例的地方。typedef uint8_t msgdata[150]; msgdata是一个衰减为指针的数组。因此,*msgdata是数组,并且数组是(衰减到)指向其开头的指针。
    因此,您可能会争辩:没什么大不了的,我可以保留多余的*,对吗?
    没有
    因为总有一天,有人会将代码更改为:
    class msgdata
    {
        int something_super_useful;
        uint8_t msgdata[150];
    };
    
    在这种情况下,编译器将捕获它,但是通常来说,间接级别错误可能会编译为细微的崩溃。找到无关的*可能需要您花费数小时或数天的时间。

    关于c++ - 使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么或者为什么不?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63364253/

    10-11 20:31
    查看更多