memset 对浮点数组做了什么?

What is memset doing to a float array?

我最近在网上找到一段代码,看起来有点像这样:

#include <stdio.h>
#include <string.h>

int main() {
    float m[10];
    memset(m, 0, 20); 
}

我还看到了一个我认为是正确的片段:

memset(m, 0, sizeof m); 

当尝试使用此代码段打印出第一个示例的所有值时:

for (int i = 0; i < 20; i++) {
    printf("%f, \n", m[i]);
}

它产生这样的输出:

0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
-0.000000, 
-4587372491414098149376.000000, 
-0.000013, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000, 
0.000000

重新编译时值发生变化。

现在我有几个问题:

Why can memset write to a float-array more than what was allocated and why can't you do that with a char-array?

memset(m, 0, 20);,正如问题最初显示的那样,写入的内容不超过分配的内容。通常,float在C实现中是四个字节,所以float m[10];分配40个字节,memset(m, 0, 20);写20个。

在新代码中,memset(m, 0, sizeof m);m 写入的字节数与它写入的字节数一样多,不多也不少。

如果 memset 被要求写更多,您可以尝试这样做的原因是 C 实现通常不进行安全检查操作,并且 C 标准不要求它们这样做。

Why is it so inconsistent?

没有什么不一致的。 memsetm的前20个字节写0,也就是浮点数0的编码,float常用的格式(IEEE-754 binary32,也叫“单精度”)。

之后的字节没有被写入,所以打印它们使用的是未初始化的数据。 C 标准说未初始化对象的值未确定。一个常见的结果是程序使用内存中已经存在的任何内容。那可能是零,也可能是其他东西。

但是,使用循环 for (int i = 0; i < 20; i++),您超出了 m 中的 10 个元素。然后访问 m[i] 的行为不是由 C 标准定义的。如上所述,一个常见的结果是程序访问计算出的内存并使用其中的任何内容。然而,各种其他行为也是可能的,包括由于尝试访问未映射的内存而导致崩溃,或者编译器在优化期间用备用代码替换未定义的代码。

Why does changing the second value of memset not change the output?

它会,取决于你把它改成什么。该字节的某些值可能会导致 float 值非常小,它们仍然打印为“0.000000”。例如,如果字节设置为 1,使每个 float 中的 32 位 0x01010101,它们表示 float 值 8,454,401•2− 148 = 2.36942782761723955384693006253917004604239556833255136345174597127722672385008451101384707726538181304931640625•10[=8[31=]3]3]。

如果您使用 64 作为 memset 的第二个参数,这些位将被设置为 0x40404040,其编码值为 3.0039215087890625,因此将打印“3.003922”。

Memsetfloat 数组没有任何作用。你只有一个包含 10 个浮点数的数组,你使用了一个覆盖 20 个浮点数的循环,这意味着,由于 C 不检查数组边界......不是。我不会在这里重复其他答案中已经说过的内容,但是您在调整 C 对象的大小时遇到​​了问题。 sizeof 运算符是您的朋友。在将参数传递给 memcpymalloc 之类的函数时使用它而不是使用常量,因此如果您调整对象的大小,您仍然可以,而无需更改常量值。