Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么?_C++_Arrays_Pointers_Typedef_Dereference - Fatal编程技术网

C++ 使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么?

C++ 使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么?,c++,arrays,pointers,typedef,dereference,C++,Arrays,Pointers,Typedef,Dereference,好的,在开始之前,我会说我不完全确定如何描述这个问题和我目前的困惑,所以我会尽我所能提供一些例子 问题: 在memcpy调用中使用typedef-ed固定长度数组的两种方法(如下“上下文”中所示)中,哪一种是正确的?或者它们是等价的 (我开始思考它们是等效的——下面的“注释”中有一些实验) 上下文 考虑以下类型定义typedef uint8_t msgdata[150]和库接口const msgdata*IRead_GetMsgData(void) 在我的代码中,我使用IRead_GetMsgD

好的,在开始之前,我会说我不完全确定如何描述这个问题和我目前的困惑,所以我会尽我所能提供一些例子

问题: 在memcpy调用中使用typedef-ed固定长度数组的两种方法(如下“上下文”中所示)中,哪一种是正确的?或者它们是等价的

(我开始思考它们是等效的——下面的“注释”中有一些实验)

上下文 考虑以下类型定义
typedef uint8_t msgdata[150]和库接口
const msgdata*IRead_GetMsgData(void)

在我的代码中,我使用IRead_GetMsgData和memcpy将结果放入另一个uint8_t缓冲区(下面的人为示例)

现在,这很好地工作并通过了我们的单元测试,但它开始了我们团队之间关于在这种情况下是否应该取消引用myData的讨论。事实证明,不去引用myData也可以工作并通过我们所有的单元测试

    std::memcpy(mBuff, myData, sizeof(msgdata)); //This works fine, too
在编写memcpy调用时,我的想法是,因为myData的类型是msgdata*,对它的解引用将返回指向msgdata的数据,这是一个uint8_t数组。 例如

我试图寻找类似问题的讨论,但还没有找到任何相关的内容:

  • -如何使用/格式化typedef
  • -如何取消对类型定义数组的引用并访问其元素
  • -再次说明如何格式化typedef
列表中的最后一个对我来说是最相关的,因为被接受的答案很好地说明了这一点(我的重点)

[这种类型的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
版本发生了什么…

在我看来,这个代码是完全错误的。我也会接受另一种观点“代码非常误导”

当您取消引用
*myData
时,会误导读者。显然,memcpy需要指向
msgdata
的指针,因此不需要解引用星号
myData
已经是指针。引入额外的解引用会破坏代码

但它不。。。为什么?

这就是特定用例的作用所在<代码>类型定义uint8_t msgdata[150]
msgdata是一个衰减为指针的数组。因此,
*msgdata
是数组,数组是(衰减为)指向其开头的指针

所以,你可能会说:没什么大不了的,我可以把多余的
*
放进去,对吗

因为有一天,有人会将代码更改为:

class msgdata
{
    int something_super_useful;
    uint8_t msgdata[150];
};

在这种情况下,编译器将捕获它,但一般来说,间接层错误可能会编译成一个微妙的崩溃。您可能需要数小时或数天才能找到无关的
*

标准布局组合的地址与其第一个成员的地址相同…假设typedef明天更改为
struct msgdata{uint_8 data[150];},您应该如何做才能使您的代码受影响最小?谢谢您的回答!当然,你是对的——这很有道理。关于间接性的警告也被注意到了!将
memcpy
调用替换为
std::copy\n
,感觉也是一种更安全的解决方案。在这种情况下,需要取消引用
msgdata*
std::copy\n(*myData,sizeof(msgdata),mBuff)。据我所知,在这种情况下,撤销引用是安全的(不仅如此,而且是必需的),因为重新定义msgdata没有风险。如果将其重新定义为与
legacyinputiator
不兼容的类型(例如示例中的类),则对copy\n的调用将无法编译。这似乎是一个更合理的解决方案吗?似乎是合理的,尽管我不熟悉copy\n。很好的发现:-)
    std::memcpy(arr, data, size);
    std::memcpy(arr, pData, size);
    std::memcpy(arr, *pData, size);
//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));
    }
}
class msgdata
{
    int something_super_useful;
    uint8_t msgdata[150];
};