为啥“memset(arr, -1, sizeof(arr)/sizeof(int))”不能将整数数组清除为-1?

Posted

技术标签:

【中文标题】为啥“memset(arr, -1, sizeof(arr)/sizeof(int))”不能将整数数组清除为-1?【英文标题】:Why does "memset(arr, -1, sizeof(arr)/sizeof(int))" not clear an integer array to -1?为什么“memset(arr, -1, sizeof(arr)/sizeof(int))”不能将整数数组清除为-1? 【发布时间】:2011-11-04 08:51:44 【问题描述】:

不能在整数数组上使用memset 吗?我尝试了以下memset 调用,但在int 数组中没有得到正确的整数值。

int arr[5];
memset (arr, -1, sizeof(arr)/sizeof(int));

我得到的值是:

arr[0] = -1
arr[1] = 255
arr[2] = 0
arr[3] = 0
arr[4] = 0

【问题讨论】:

这样做可能更容易:int arr[5] = -1; @Tom Dignan:除了只将第一个元素初始化为-1,其余的都初始化为0。 【参考方案1】:

为什么要分工?

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

您的版本 sizeof(arr)/sizeof(int) 为您提供数组中的元素数量。

【讨论】:

请注意,memset() 在寻址位置设置 bytes 的值,而不是多少“项目”。您希望将 5 个整数的字节数设置为 -1。这样做只会碰巧将 int 值设置为 -1 作为格式的巧合。 @Jeff:确实,巧合,因为 -1 的 int 通常是 $FFFFFFFF(假设 32 位 int 和二进制补码),而 -1 的字节是 $FF。如果他选择 -2 ($FE),它将变为 $FEFEFEFE,它是 -16843010 的 int。【参考方案2】:

改成memset (arr, -1, sizeof(arr));

请注意,对于 0 和 -1 以外的其他值,这将不起作用,因为 memset 设置了以 *ptr 指示的变量开头的内存块的字节值,用于以下内容num 字节。

void * memset ( void * ptr, int value, size_t num );

而且由于int 表示在多个字节上,因此您将无法获得数组中整数的所需值。

例外情况:

0 是一个例外,因为如果将所有字节设置为 0,则该值将为零 -1 是另一个例外,因为 Patrick 强调 -1 在 int8_t 中是 0xff (=255),在 int32_t 中是 0xffffffff

你得到的原因:

arr[0] = -1
arr[1] = 255
arr[2] = 0
arr[3] = 0
arr[4] = 0

是因为,在您的情况下,int 的长度为 4 个字节(32 位表示),数组的字节长度为 20(=5*4),而您仅将 5 个字节设置为 -1( =255) 而不是 20。

【讨论】:

好吧,在这种特殊情况下(将 -1 作为值)memset 确实有效。因为 -1 在 int8_t 中是 0xff,在 int32_t 中是 0xffffffff 等等。 IOW:memset 适用于 0 和 -1,但对所有其他情况都不是很有用。 你是对的帕特里克,谢谢你.. 我相应地改变了我的答案 @Patrick B. :它可以在许多平台上正常工作,但不是全部。并非所有平台都使用二进制补码,您还可以通过使用memset 初始化int 来触发陷阱表示。 所有四个字节都具有相同值的每个int都可以使用memset,而不仅仅是0和-1 @LưuVĩnhPhúc 但是除了 0 之外的表示是否有保证? ***.com/q/11138188/895245 对 0 说是,但我认为对其他人来说不是,因为我们不知道填充和符号位在每个 int 中的位置。【参考方案3】:

不要使用memset 来初始化单字节数据类型以外的任何东西。

乍一看,它似乎应该适用于将 int 初始化为 0-1 (并且在许多系统上它会起作用),但是你没有考虑到这种可能性您可能会生成陷阱表示,从而导致未定义的行为,或者整数表示为 not necessarily two's complement 的事实。

int 的数组初始化为-1 的正确方法是遍历数组,并显式设置每个值。

【讨论】:

我认为这个答案应该通过诸如“不要使用memset() ... 如果你想编写绝对可移植的代码”这样的子句来思考。大多数人既不编写也不打算编写可移植代码。当代码适用于两种架构时,大多数人称其为“可移植的”。 “正确的方式……”中的“正确”一词也可以更改为“便携式”。如果您不尝试编写绝对可移植的代码,那么它的正确性既不高也不低。 +1 @Complicatedseebio 完全同意,太多的程序员用“正确”和“stl this”之类的东西让人们大吃一惊。他们经常过度关注特定问题需要什么。 @Complicated see bio @Adam :问题是,使用循环初始化 int 的数组可以保证在所有情况下都有效,而使用 memset 可能无法正确执行(或者更糟的是可能似乎工作)。我不会说你不能使用memset,如果你对代码将运行的平台有深入的了解,并且知道它不会引起问题。但是我对可能阅读此答案的每个人的平台都不了解,因此我更愿意安全行事。我希望这能平衡我在回答中使用的一些“极端”(为了论证)。 支持 Sander,我不明白为什么 -1 对我不起作用,直到我意识到我正在使用的机器不是 2 补码。 @capitano666 - 只是好奇 - 你用的是什么处理器(“机器”)?【参考方案4】:

您可以通过直接初始化数组来节省一些输入:

int arr[5] = -1, -1, -1, -1, -1; 

那条线比 memset 短,而且它也有效。

【讨论】:

+1 表示数组初始值设定项,尽管它仅对少数值有用。 也可以将其缩写并省略元素数量的明确说明,因为编译器通过初始化次数来检测元素数量:int arr[] = -1, -1, -1, -1, -1;【参考方案5】:

gcc 提供了一个很好的数组初始化快捷方式

int arr[32] = [0 ... 10] = 3, [11 ... 31] = 4

注意...前后的空格

【讨论】:

【参考方案6】:
void * memset ( void * ptr, int value, size_t num );

当应用于设置字符数组时,此函数在大多数系统上都能很好地工作。 它将 ptr 指向的内存块的第一个 num BYTES 设置为指定值(解释为无符号字符)。 memset-C++ Reference 它每次操作一个字节。因此,如果您为第二个参数分配不超过 0xff 的 int 值,则它可以正常工作。

至于你的版本,第三个参数是数组元素的数量,所以你得到了你的输出。 实际上,您应该将第三个参数分配给您想要的字节数。

所以正确的版本应该是这样的:

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

【讨论】:

以上是关于为啥“memset(arr, -1, sizeof(arr)/sizeof(int))”不能将整数数组清除为-1?的主要内容,如果未能解决你的问题,请参考以下文章

你应该同步运行方法吗?为啥或者为啥不?

为啥使用 glTranslatef?为啥不直接更改渲染坐标?

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]