C++ 使用指向typedef固定长度数组的指针执行memcpy时是否需要取消引用?为什么?
好的,在开始之前,我会说我不完全确定如何描述这个问题和我目前的困惑,所以我会尽我所能提供一些例子 问题: 在memcpy调用中使用typedef-ed固定长度数组的两种方法(如下“上下文”中所示)中,哪一种是正确的?或者它们是等价的 (我开始思考它们是等效的——下面的“注释”中有一些实验) 上下文 考虑以下类型定义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
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];
};