【问题标题】:How memset initializes an array of integers by -1?memset如何通过-1初始化一个整数数组?
【发布时间】:2014-08-04 03:41:08
【问题描述】:

manpage 说的是memset

#include <string.h>
void *memset(void *s, int c, size_t n)

memset() 函数用常量字节c 填充s 指向的内存区域的第一个n 字节

很明显memset不能用来初始化int数组如下图:

int a[10];
memset(a, 1, sizeof(a));  

这是因为int 由 4 个字节(比如说)表示,而数组a 中的整数无法获得所需的值。
但我经常看到程序员使用memsetint 数组元素设置为0-1

int a[10];
int b[10];
memset(a, 0, sizeof(a));  
memset(b, -1, sizeof(b));  

根据我的理解,使用整数 0 初始化是可以的,因为 0 可以用 1 个字节表示(在这种情况下我可能错了)。但是如何用-1(4 字节值)初始化b

【问题讨论】:

  • 投反对票,想解释一下吗?这个问题与这个网站或其他东西无关吗?
  • 您对使用0 进行初始化的原因有点错误。没关系,因为0 适合unsigned char(因此在用作memset 的第二个参数时不会被截断)因为sizeof(int) 的内存中的位模式-字节零与内存中sizeof(int) 连续一字节零的位模式相同。这两件事都必须是真实的才能起作用。事实上,在二进制补码算术中,这些情况恰好适用于两个数字:0-1
  • @zwol:嗯?第一句话说的是零,所以对于-1 来说不是真的。因此,大概您打算隐式参数化第一句:如果 int 的值为 x 的位与 sizeof(int) 的位相同,则它适用于 x unsigned char 每个都有值 x。此外,我们必须将具有值 xunsigned char 视为由 x 转换为 unsigned char 的结果,因为 -1 是不可表示的。如果是这样,那么 0 和 -1 是唯一这样的值是不正确的。 16,843,009 • x 适用于任何整数 0 ≤ x
  • @zwol:除了C不要求不同宽度的整数中的位位置表示相同的值。
  • @EricPostpischil 我不明白你的例子。任何 char 类型都不能表示 16,843,009 的倍数(好吧,除非您使用的是 CHAR_BIT &gt;= 25 的机器。)

标签: c++ c arrays twos-complement memset


【解决方案1】:

奇怪的是,这与 -1 一起工作的原因与它与零一起工作的原因完全相同:在two's complement binary representation 中,-1 的所有位都有1s,无论大小如何整数,因此在二进制补码硬件上用填充了所有 1s 的字节填充一个区域会产生一个有 -1 有符号 ints、longs 和 shorts 的区域。

在不同于二进制补码的硬件上,结果会有所不同。 -1 整数常量将被转换为所有的 unsigned char,因为该标准具体说明了必须如何执行转换。但是,所有位都设置为1 的字节区域将根据平台规则被解释为整数值。例如,在符号和大小硬件上,数组的所有元素都将包含相应类型的最小负值。

【讨论】:

  • 使用~0 不会有效地相同(并且更清晰)?
  • @FiddlingBits 是的,使用~0 肯定会避免这里的混乱。
  • @hacks 如果你用全1位模式填充一个内存区域,该区域对应于某个整数类型的sizeofintlongshort),然后将该区域重新解释为相应的整数类型,您将在具有二进制补码表示的计算机上看到 -1。请注意,在极少数情况下,当您拥有符号幅度硬件时,您会看到该硬件上可表示的最小负整数(我从未见过这样的硬件,甚至没有人提到见过这样的硬件,但我听说它确实存在) .
  • @hacks 你是对的,使用-1 作为“用全1 填充的字节”的“快捷方式”是特定于平台的。我对此进行了一些澄清,以及上面的长评论。谢谢!
  • @chux 标准规定,为了将负整数值转换为unsigned,编译器必须从 2^N 中减去负值的大小,其中 N 是无符号整数类型。这里,N 是 8,所以结果是 256-1=255,一个无符号值。这就是他们避免在不需要 2s 补码表示的情况下定义流程实现的方式。这就是为什么我的理解是-1 将被转换为全一的位模式,而不管目标平台上的负数表示方式如何。
【解决方案2】:

当一个数的所有位都是0时,它的值也是0。但是,如果所有位都是 1,则值为 -1

如果我们写int a[2],则分配4x2字节的内存,其中包含随机/垃圾位-

00110000 00100101 11100011 11110010    11110101 10001001 00111000 00010001

然后,我们写memset(a, 0, sizeof(a))。现在,memset() 逐字节工作,0 的一个字节表示(unsigned char)是00000000。所以,它变成了-

00000000 00000000 00000000 00000000    00000000 00000000 00000000 00000000

因此,a[0]a[1] 都被初始化为 0


现在,让我们看看memset(a, -1, sizeof(a))-1 的一个字节是11111111。而且,我们得到-

11111111 11111111 11111111 11111111    11111111 11111111 11111111 11111111

这里,a[0]a[1] 的值都为 -1


但是,对于memset(a, 1, sizeof(a)):一个字节中的100000001-

00000001 00000001 00000001 00000001    00000001 00000001 00000001 00000001

因此,该值将是 - 16843009

【讨论】:

  • void *memset( void *dest, int ch, size_t count ); => 将值ch(转换为unsigned char后)复制到dest指向的对象的第一个count个字符中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
  • 2012-11-08
  • 1970-01-01
  • 2022-01-23
  • 2010-11-05
  • 1970-01-01
  • 2011-03-24
相关资源
最近更新 更多