C++ memcpy() 棘手的使用,需要行为理解

C++ memcpy() tricky use, behavior understanding needed

本文关键字:memcpy C++      更新时间:2023-10-16
为了

修复旧程序而进行反编译可能会很痛苦。

因为我是一名 C# 开发人员,所以有些奇怪的东西我不明白。我需要一位C++技巧专家来帮助我理解"memcpy()"的行为。

这是我玩的:

unsigned char sdata[] =  { 0x54, 
                           ... many values (=4100) ..., 
                           0x00 };

然后

unsigned char BF_PTransformed[4*18] = { 0xC6, 
                                    ... many values (=72) ..., 
                                        0x7B };

struct BLOWFISH_CTX 
{
  unsigned long P[16 + 2];
  unsigned long S[4][256];
};

以下是memcpy()电话:

void BFInit() 
{
    BLOWFISH_CTX* ctx = &this->BlowfishContext; 
    memcpy((void*)ctx->P, this->BF_PTransformed, 18*4);
    memcpy((void*)ctx->S, (void*)this->sdata, 0x100*4*4);
}

问题

我不明白这在字节数高于数组目标长度的情况下如何表现。这是关于数据类型的吗?

有人可以解释一下,以便 C# 开发人员可以理解它吗?

(甚至不要试图提及河豚这个词。 2天在这个"特殊"的实现上让我感到恶心啊哈)

我不明白,字节数比数组目标长度高,如何表现 这是关于数据类型的吗?

首先,memcpy对字节而不是数组元素进行操作。所以如果你想复制一个数组int[10],例如,你告诉memcpy复制40字节(10*sizeof(int))。因此,传递给 memcpy 的参数(在本例中为 40)可以大于数组元素的数量 (10),因为每个数组元素占用多个字节。

其次,如果你真的告诉memcpy复制数组的末尾(比如,如果我们在上面的例子中传递 43 作为参数给memcpy),那么你就会有未定义的行为

在 C 和 C++ 中,许多错误条件不需要在编译时运行时检测。在 C# 中,如果在运行时尝试非法操作,则会引发异常。

在C++,在某些情况下也会发生这种情况。但在许多其他情况下,根本无法检测到错误,并且发生的情况是不确定的。应用程序可能会崩溃,或者可能会继续以损坏的状态运行。它可能成为一个安全漏洞,或者它可能(理论上)让恶魔从你的鼻子里飞出来。语言规范只是没有说明应该发生什么。

读取数组的末尾(就像你告诉memcpy复制超过数组长度一样)就是这样一种情况。如果您尝试这样做,您的应用程序就会有一个错误,但是当您尝试运行它时,无法说明它将如何运行。如果你幸运的话,它会崩溃。在最坏的情况下,它将继续运行,因为这样它就会处于不一致的状态,并且以后可能会崩溃(使错误更难诊断),或者它可能不是崩溃,而是产生错误的结果,或者当您在计算机上运行它时,它可能看起来正常工作,但在客户运行应用程序时表现出任何这些行为。

未定义的行为是不好的。不惜一切代价避免。

memcpy length 参数以字节为单位,而不是数组元素。

代码最好写成:

memcpy((void*)ctx->P, this->BF_PTransformed, 18 * sizeof(unsigned long));
memcpy((void*)ctx->S, (void*)this->sdata, 0x100 * 4 * sizeof(unsigned long));