c++ - 使用指向 typedef 固定长度数组的指针执行 memcpy 时是否需要取消引用?为什么或者为什么不?
问题描述
好的 - 所以我会先说我不完全确定如何描述这个问题和我目前的困惑,所以我会尽力提供例子。
问题
在 memcpy 调用中使用 typedef 固定长度数组的两种方法中哪一种是正确的?或者它们是等价的吗?
(我开始认为它们是等效的——在下面的“注释”下进行了一些实验)。
语境
考虑以下 typedeftypedef uint8_t msgdata[150];
和库接口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]
我尝试搜索类似问题的讨论,但尚未找到任何相关的内容:
- 使用带有固定长度数组 typedef 的 new - 如何使用/格式化 typedef
- 如何正确取消引用 typedef 数组指针?- 如何取消引用类型定义的数组并访问其元素
- 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
版本发生了什么......
解决方案
这段代码,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 需要一个指向 a 的指针msgdata
,因此不需要取消引用星号。myData
已经是一个指针。引入额外的取消引用会破坏代码。
但它没有......为什么?
那就是您的特定用例开始的地方。typedef uint8_t msgdata[150];
msgdata 是一个衰减为指针的数组。所以,*msgdata
是数组,而数组是(衰减为)指向其开头的指针。
所以,你可以争辩说:没什么大不了的,我可以把多余的留*
在里面,对吧?
没有。
因为有一天,有人会把代码改成:
class msgdata
{
int something_super_useful;
uint8_t msgdata[150];
};
在这种情况下,编译器会捕获它,但一般来说,间接级别错误可能会编译为细微的崩溃。您需要数小时或数天才能找到无关的*
.
推荐阅读
- c# - 0x 在使用 web api 传递文件时被插入数据库
- c# - 从 ListView 显示所选图像的新窗口无权访问图像路径
- sql - 如何将所有表数据转换为 nvarchar?
- python - Sympy,如何在给定范围内求解具有 2 个未知数的方程
- javascript - 如何推送包含反应文件夹作为客户端文件夹的节点应用程序?
- c++ - 在 C++ 中使用 FMT 进行字符串插值的链接器错误
- join - Power BI-BigQuery 连接错误:“不能在没有字段相等条件的情况下使用”
- c# - 为什么可能多次枚举 IEnumerable 警告 *未显示 *
- java - 以对象为值在 HashMap 中动态嵌套键值
- c++ - C++:矩阵高斯消除不起作用:使用单维数组存储元素