繁体   English   中英

为什么 memset() 错误地初始化 int?

[英]Why is memset() incorrectly initializing int?

为什么以下程序的输出是84215045

int grid[110];
int main()
{
    memset(grid, 5, 100 * sizeof(int));
    printf("%d", grid[0]);
    return 0;
}

memset将目标缓冲区的每个字节设置为指定值。 在您的系统上,一个int是四个字节,在调用memset之后每个字节是 5。 因此, grid[0]的值为0x05050505 (十六进制),即十进制的84215045

一些平台为memset提供了替代 API,可以将更广泛的模式写入目标缓冲区; 例如,在 OS X 或 iOS 上,您可以使用:

int pattern = 5;
memset_pattern4(grid, &pattern, sizeof grid);

获得您似乎期望的行为。 你的目标是什么平台?

在 C++ 中,您应该只使用std::fill_n

std::fill_n(grid, 100, 5);
memset(grid, 5, 100 * sizeof(int));

您正在设置 400 个字节,从(char*)grid开始,到(char*)grid + (100 * sizeof(int))结束,到值5 (这里需要强制转换,因为memset处理字节,而指针算术交易objects

十六进制的842150450x05050505 由于int (在您的平台/编译器/等上)由四个字节表示,因此当您打印它时,您会得到“四个五”。

memset是关于设置字节,而不是值。 在 C++ 中设置数组值的众多方法之一是std::fill_n

std::fill_n(grid, 100, 5);

不要使用 memset。

您将内存的每个字节[]设置为 5。每个 int 的长度为 4 个字节[5][5][5][5] ,编译器将其正确解释为 5*256*256*256 + 5* 256*256 + 5*256 + 5 = 84215045。相反,使用 for 循环,它也不需要 sizeof()。 一般来说, sizeof() 意味着你正在做一些艰难的事情。

for(int i=0; i<110; ++i)
    grid[i] = 5;

好吧, memset使用选定的值写入字节。 因此 int 看起来像这样:

00000101 00000101 00000101 00000101

然后将其解释为 84215045。

你实际上并没有说你想让你的程序做什么。

假设您要将grid的前 100 个元素中的每一个设置为 5(并忽略100110的差异),只需执行以下操作:

for (int i = 0; i < 100; i ++) {
    grid[i] = 5;
}

我了解您担心速度,但您的担心可能是错误的。 一方面, memset()可能会被优化,因此比简单的循环更快。 另一方面,优化可能包括一次写入多个字节,这就是这个循环所做的。 另一方面, memset()无论如何都是一个循环; 显式编写循环而不是将其埋在函数调用中并不会改变这一点。 另一方面,即使循环很慢,也可能无关紧要。 专注于编写清晰的代码,如果实际测量表明存在严重的性能问题,则考虑对其进行优化。

您编写问题所花费的时间比您的计算机设置grid所花费的时间要多很多数量级。

最后,在我手忙脚乱(为时已晚!)之前,如果memset()不能满足您的要求,那么它的速度并不重要。 (根本不设置grid甚至更快!)

如果你在 shell 上输入man memset ,它会告诉你

void * memset(void *b, int c, size_t len)

一个简单的英语解释是,它填充一个长度为len的字节串b ,每个字节都有一个值c

对于你的情况,

memset(grid, 5, 100 * sizeof(int));

由于sizeof(int)==4 ,因此上面的代码片段看起来像:

for (int i=0; i<100; i++)
    grid[i]=0x05050505;

或者

char *grid2 = (char*)grid;
for (int i=0; i<100*sizeof(int); i++)
    grid2[i]=0x05;

它将打印出84215045

但在大多数 C 代码中,我们希望将一块内存块初始化为零。

  • char类型 --> \\0NUL
  • int类型 --> 0
  • float类型 --> 0.0f
  • double类型 --> 0.0
  • 指针类型 --> nullptr

gccclang等现代编译器可以自动为您处理好这个问题。

// variadic length array (VLA) introduced in C99
int len = 20;
char carr[len];
int iarr[len];
float farr[len];
double darr[len];
memset(carr, 0, sizeof(char)*len);
memset(iarr, 0, sizeof(int)*len);
memset(farr, 0, sizeof(float)*len);
memset(darr, 0, sizeof(double)*len);
for (int i=0; i<len; i++)
{
    printf("%2d: %c\n", i, carr[i]);
    printf("%2d: %i\n", i, iarr[i]);
    printf("%2d: %f\n", i, farr[i]);
    printf("%2d: %lf\n", i, darr[i]);
}

但请注意,C ISO 委员会并没有强加这样的定义,它是特定于编译器的。

此代码已经过测试。 这是一种将“整数”数组设置为 0 到 255 之间的值的方法。

MinColCost=new unsigned char[(Len+1) * sizeof(int)];

memset(MinColCost,0x5,(Len+1)*sizeof(int));

memset(MinColCost,0xff,(Len+1)*sizeof(int));

由于 memset 写入字节,我通常使用它将一个 int 数组设置为零,例如:

int a[100];
memset(a,0,sizeof(a));

或者您可以使用它来设置 char 数组,因为 char 正是一个字节:

char a[100];
memset(a,'*',sizeof(a));

更重要的是,一个 int 数组也可以通过 memset 设置为 -1:

memset(a,-1,sizeof(a));

这是因为 -1 在 int 中是 0xffffffff,在 char(一个字节)中是 0xff。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM