memset() 在 C++ 中的工作原理

Posted

技术标签:

【中文标题】memset() 在 C++ 中的工作原理【英文标题】:How memset() works in c++ 【发布时间】:2018-09-03 16:57:19 【问题描述】:

我创建了一个布尔二维数组并像这样使用memset

bool chk[3][3];

memset(chk, 1, 9*sizeof(chk[0]));

我使用以下代码块得到了预期的输出(每行有 1 个)

for(int i = 0 ; i < 3; i++)
    for(int j = 0; j < 3; j++)
        cout<<chk[i][j] <<" ";
    cout<<endl;

但是当我尝试操作数组时,我得到了意想不到的结果

然后我尝试了

memset(chk, 1, 9*sizeof(chk[0][0]));

这次一切都很好,得到了我预期的结果(操作后)

你能帮我指出 memset() 中到底发生了什么吗?

【问题讨论】:

sizeof(chk[0]) == sizeof(bool[3]) == 3*sizeof(bool)。您的程序通过缓冲区溢出表现出未定义的行为。 您系统上的bool 有多大? 如果你确定你总是有一个真正的数组(而不是一个指向动态分配内存的指针),最安全的选择是简单地使用sizeof(chk)。显然,使用文字 9 很容易导致数组尺寸发生变化(这个问题与类型无关,因此sizeof(chk[0]) 中的大小不匹配)。 memset 不是最好的工具,因为每个bool 的每个字节都将设置为一个。修复大小问题并使用int 尝试此操作,您会看到输出类似于 16843009 而不是 1。您可以使用 bool 解决它,因为所有不是 0 的东西都是正确的,但是您做了很多次工作 @Swordfish 因为他不应该使用 memset,除非将它设置为 0,在这种情况下他应该使用值初始化。所以他需要数组的大小,而不是数组使用的存储大小。硬编码数组大小正在招致糟糕的一天发生 【参考方案1】:

你的第一个代码sn-p中的memset调用存在三个问题:

    大小计算不正确。您可以使用3*sizeof(chk[0]) 而不是9*sizeof(chk[0])。但实际上你应该只使用sizeof(chk),因为你有一个局部变量,而不是一个指针,就像使用正式参数一样。

    标准不保证true 的内存表示是位模式1 的假设。在实践中它会成立,但最好直接使用值true 而不是不必要的假设。

    在 C++ 中,只需将变量初始化为零以使其全为零,例如bool chk[3][3] = ;,或使用std::fill 用给定值填充数组,例如fill( &amp;chk[0][0], &amp;chk[0][0] + 9, true );


附录:为了迂腐,在第 1 点有一个假设 bool 是 1 个字节。这也是一个在实践中成立但不受标准保证的假设。很高兴使用std::fill 不是问题。

【讨论】:

零初始化也不会将值设置为 true。 @user2079303:你可以使用std::fill。要增加整数数组中的值,您可以使用std::iota。这些是更多类型安全的函数。 +2 填充,如果可以的话。不能保证 bool 是 1 个字节,因此 memset 可能会写出有趣的模式,正如 @user4581301 已经观察到的那样。 是否允许迭代第一个子数组超出其边界,以便迭代兄弟数组?我在 SO 上看到过答案,声称这是 UB。 @user2079303:标准通过sizeof 的要求保证数组是连续的,没有填充。所以是的,没关系。【参考方案2】:

sizeof(chk[0])sizeof(bool[3]) 明显不同于 sizeof(chk[0][0])sizeof(bool)

使用memset(chk, 1, 9*sizeof(chk[0]));,您写入超出数组chk 的范围并获得未定义的行为。

【讨论】:

【参考方案3】:

我们来看看std::memset的文档是怎么说的:

如果 count 大于 dest 指向的对象的大小,则行为未定义。

在第一个代码中,9*sizeof(chk[0]) 大于chk 的大小,因此程序的行为是未定义的。

memset(chk, 1, sizeof chk) 会更简单,就大小而言显然是正确的。

【讨论】:

考虑到“新用户”这一手,您可能会详细说明chk[0] 的类型和可能大小...考虑到 C 和 C++ 有趣的数组语义,这并不完全明显。【参考方案4】:

sizeof(array) 显然会以字节为单位返回数组的大小。在第一种情况下,您提交给操作员的数组是子数组之一。 C++ 中的多维数组不是。它们是数组的一维数组。执行sizeof(chk) 评估整个数组的大小并将其除以sizeof(chk[0][0]) 以获得元素数量。不要使用memset,因为如果会对布尔的二进制表示做一些奇怪的事情,请使用std::fill

【讨论】:

"执行 sizeof(chk) 来评估整个数组的大小并将其除以 sizeof(chk[0][0]) 以获得元素的数量。"我发现这具有误导性,因为问题是关于 memset(),它采用字节数而不是元素数。 @Swordfish memset 是错误的工具,正如 Swift 指出的那样;元素的数量可用于填充,如 Alf 的示例中所示。

以上是关于memset() 在 C++ 中的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

C++ 参考的工作原理

浅谈C++编译原理 ------ C++编译器与链接器工作原理

C++中虚函数工作原理和(虚)继承类…

C++ 放置新的工作原理是啥?

基于arm的C++反汇编 函数的工作原理

memset 初始化数组 & 实现原理