memcpy
如果缓冲区大小足够,调用两个不同的结构是否会保留原始数据?如果它们各自的数据类型重叠,是否定义为使用先前数据类型的数据检索另一种数据类型的值?
这对于两种 c/cpp 语言应该是相似的,但我在 cpp 中提供了一个示例 -
#include <iostream>
#include <cstring>
using namespace std;
struct A{
int a;
char b[10];
};
struct B{
int ba;
int bb;
};
int main(){
B tmp;
tmp.ba = 50;
tmp.bb = 24;
cout << tmp.ba << tmp.bb << "\n";
// everything is fine yet
A obj;
memcpy(&obj, &tmp, sizeof(tmp));
// 1. is this valid?
cout << obj.a << "\n";
B newB;
memcpy(&newB, &obj, sizeof(newB));
// 2. Are these valid?
cout << newB.ba << newB.bb << "\n";
}
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我评论了第 1 条和第 2 条评论,它们是否有效?如果提供了足够的缓冲区,数据是否会被保留?我们可以轻而易举地做到这一点吗?
与它相关的结构和其他函数在 C 库中,但我们将使用 C++ 来使用和编译它。
除了遵循 C 标准之外,C++ 标准没有指定 的行为memcpy
。(也许是为了避免解决这样的问题!)。在 C 标准中,它被定义为等价于字符类型副本1的序列。
因此,将其memcpy(&obj, &tmp, sizeof(tmp));
视为以下似乎是合理的:
unsigned char *dst = (char *)&obj;
unsigned char *src = (char *)&tmp;
for (size_t i = 0; i != sizeof tmp; ++i)
dst[i] = src[i];
Run Code Online (Sandbox Code Playgroud)
然后使用 C++ 标准来覆盖该代码。
现在的问题是:
&tmp
,&obj
实际上给对象的起始地址?obj
?tmp
呢?obj
?问题 1:是的,[class.mem]/19 涵盖了这一点,因为没有基类子对象(并且它不会重载operator&
)。
问题 2:我找不到任何专门涉及此问题的文本;但是,如果不允许写入填充字节,则标准中将类类型对象复制到字符缓冲区并返回到对象中的示例将不起作用。
问题 3:[dcl.init]/12 中的一些文本明确允许对未初始化数据使用上述代码;并且目的地将包含不确定的值。因此,如果源中未初始化的填充字节仅映射到目标中的未初始化填充字节,那很好。但是如果它们被映射到目的地的子对象,那么这些对象将具有不确定的价值。
问题 4:这里没有问题,严格的别名规则允许对象通过字符类型表达式覆盖其部分(或全部)字节。稍后访问对象将产生与表示对应的值,如果它不表示值,则使用 UB。
所以,总而言之,我认为你的具体例子是可以的,假设sizeof(A) >= sizeof(B)
.
1在 C 中,memcpy 也保留了对象的有效类型。C++ 有一个不同的对象模型,并且没有与此等效的对象模型。因此,如果您在 C 编译器中使用类似的代码,您还需要遵守两个对象中类型之间的严格别名规则。
归档时间: |
|
查看次数: |
1662 次 |
最近记录: |