为啥“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】:void * memset ( void * ptr, int value, size_t num );
当应用于设置字符数组时,该函数在大多数系统上都能很好地工作。 它将 ptr 指向的内存块的第一个 num BYTES 设置为指定值(解释为无符号字符)。 memset-C++ Reference 它每次操作一个字节。因此,如果您为第二个参数分配不超过 0xff 的 int 值,则它可以正常工作。
至于你的版本,第三个参数是数组元素的数量,所以你得到了你的输出。 实际上,您应该将第三个参数分配给您想要的字节数。
所以正确的版本应该是这样的:
memset (arr, -1, sizeof(arr));
【讨论】:
【参考方案2】:不要使用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 - 只是好奇 - 你用的是什么处理器(“机器”)?【参考方案3】:
gcc 提供了一个很好的数组初始化快捷方式
int arr[32] = [0 ... 10] = 3, [11 ... 31] = 4
注意...
前后的空格
【讨论】:
【参考方案4】:改成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 中的位置。【参考方案5】:
您可以通过直接初始化数组来节省一些输入:
int arr[5] = -1, -1, -1, -1, -1;
那条线比 memset 短,而且它也有效。
【讨论】:
+1 表示数组初始值设定项,尽管它仅对少数值有用。 也可以将其缩写并省略元素数量的明确说明,因为编译器通过初始化次数来检测元素数量:int arr[] = -1, -1, -1, -1, -1;
。【参考方案6】:
为什么要分工?
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。以上是关于为啥“memset(arr, -1, sizeof(arr)/sizeof(int))”不能将整数数组清除为-1?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用 glTranslatef?为啥不直接更改渲染坐标?
为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?