C和C ++标准对位级整数表示和操作有何看法?

我知道C和C ++标准没有规定数字的特定表示(可以是二进制补码,符号和数量等)。 但我不清楚这些标准(并且无法确定是否已经说明)知道在使用位时是否存在任何特定的限制/保证/保留表示。 尤其:

  1. 如果整数类型中的所有位都为零,那么整数整数是否代表零?
  2. 如果整数类型中的任何位是1,整数整数是否表示非零? (如果这是“是”,则会对符号和幅度等一些表示进行额外限制)
  3. 是否有保证的方法来检查是否有任何位未设置?
  4. 是否有保证的方法来检查是否设置了任何位? (#3和#4类型依赖于#1和#2,因为我知道如何设置,例如某些变量x的第5位(参见#5),我想检查变量y以查看如果它的第5位为1,我想知道if if (x & y)是否有效(因为据我所知,这取决于表示的值而不是该位是否实际为1或0))
  5. 是否有保证的方法来设置最左边和/或最右边的位? (至少比一个char c更简单的方法是所有位都为真(由c = c | ~c )并且做c = c << (CHAR_BIT - 1)来设置高位和c = c ^ (c << 1)对于低位,假设我不做任何假设,我不应该,鉴于这些问题)
  6. 如果#1的答案是“否”,那么如何迭代整数类型的位并检查每个位是1还是0?

我想我的整体问题是:C和C ++标准是否有关于位和整数的限制/保证/保留表示,尽管事实上没有规定整数的表示(如果C和C ++标准在这方面不同) ,他们的区别是什么?)

我在做作业时提出了这些问题,这需要我做一些操作(注意这些不是我作业的问题,这些都是“抽象的”)。

编辑:关于我所说的“位”,我的意思是“值形成”位而不包括“填充”位。

(1)如果整数类型中的所有位都为零,那么整数整数是否代表零?

是的,由全零组成的位模式始终表示0:

整数类型的表示应使用纯二进制计算系统定义值。 49 [§3.9.1/ 7]

49使用二进制数字0和1的整数的位置表示,其中由连续位表示的值是加法的,以1开始,并且乘以2的连续积分幂,除了具有最高位置的位之外。


(2)如果整数类型中的任何位是1,那么整数整数是否表示非零? (如果这是“是”,则会对符号和幅度等一些表示进行额外限制)

不可以。事实上,特别允许签名幅度:

[ 例如:本国际标准允许积分类型的2的补码,1的补码和带符号的幅度表示。 – 示例 ] [§3.9.1/ 7]


(3)是否有保证的方法来检查是否有任何位未设置?

如果考虑签名类型,我相信答案是“不”。 它相当于使用所有1的位模式进行相等测试,这只有在您能够生成具有所有1的位模式的带符号数的情况下才有可能。 对于无符号数,此表示是有保证的,但如果数字不可表示,则从unsigned转换为signed是未定义的:

如果目标类型是有符号的,如果它可以在目标类型(和位字段宽度)中表示,则该值不变; 否则,该值是实现定义的。 [§4.7/ 3]


(4)是否有保证的方法来检查是否设置了位?

我不这么认为,因为允许有符号幅度-0将比较等于-0。 但是应该可以使用无符号数字。


(5)有保证的方法来设置最左边和/或最右边的位吗?

同样,我认为对于无符号数字,答案是“是”,对于有符号数字,答案是“否”。 对于负数签名数字,未定义class次:

否则,如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2 E2 ,那么这就是结果值; 否则,行为未定义。 [§5.8/ 2]

您反复使用术语“所有位”,但您没有说明您所指的“所有位”。 C / C ++中整数类型的对象表示可能包括值形成位填充位 。 唯一保证不具有填充位的整数类型是[signed/unsigned] char

语言总是保证如果所有的值形成位都为零,则表示的整数值也为零。

至于填充位,事情有点复杂。 C语言的原始规范(C89 / 90以及原始C99)并不保证将所有对象位设置为零都会产生有效的整数表示。 它可能会产生无效的陷阱表示。 即在原始C(甚至在C99中)使用整数类型的memset(..., 0, ...)并不能保证对象将接收有效的零值( [signed/unsigned] char除外[signed/unsigned] char )。 这在后来的规范中有所改变,即在C99的技术勘误之一中。 现在要求整数对象中的全零位模式(涉及所有位,包括填充的位)表示有效的零值。

即在现代C中,使用memset(..., 0, ...)将任何整数对象设置为零是合法的,但只有在C99之后它才合法。

您已经获得了有关整数值表示的一些答案。 有一种方法可以保证为您提供在内存中表示的任何对象的所有单独位:将其视为unsigned char数组。 这是唯一没有填充位的整数类型,并且保证没有陷阱表示。 因此,只要您只访问第一个sizeof(T)字节,就可以将对象类型为T*的指针强制转换为unsigned char* 。 通过这种方式,您可以根据自己的喜好检查和设置所有字节(以及位)。

如果你对更多的细节感兴趣,这里我已经写了一些关于C 中整数类型的解剖的东西.C ++可能与此有所不同,特别是通过union类型惩罚,如上所述在C ++中似乎没有很好地定义。

问:如果整数类型中的任何位是1,那么整数整数是否表示非零? (如果这是“是”,则会对符号和幅度等一些表示进行额外限制)

不可以.C和C ++的标准不排除有符号幅度或一个补码,两者都有+0和-0。 虽然+0和-0必须比较相等,但它们不必具有相同的表示。

祝你现在找到一台使用有符号幅度或一个补码的机器。

如果你想要你的大脑爆炸,请考虑这个:如果你将一个int或long或long long解释为unsigned char数组(如果你想看到所有位,这是最合理的事情),你知道未定义字节顺序,例如“bigendian”与“littleendian”。 我们都(希望)知道这一点。

但更糟糕的是:int的每个位都可以存储在char数组的任何位中。 所以有32个! 通过一个真正奇怪的实现,如何将32位整数的位映射到四个8位无符号字符的数组。 幸运的是,我自己并没有遇到过两种以上的方式(我知道在真正的计算机中还有一种方法)。

如果整数类型中的所有位都为零,那么整数整数是否代表零?

编辑 :因为您现在已经澄清了您不关心填充位,所以答案实际上是“是”。 但我离开了原文:

不一定,它可能是陷阱表示。 见C99 6.2.6.1:

对于unsigned char以外的无符号整数类型,对象表示的位应分为两组:值位和填充位(不需要后者中的任何一个)

填充比特的存在允许所有0都是陷阱表示的可能性。 (正如Keith Thompson在下面的评论中所指出的,最近的C11明确指出这样的表示不是陷阱表示)。

未指定任何填充位的值

44)填充比特的某些组合可能生成陷阱表示

如果将问题限制为值和符号位,答案是肯定的,因为6.2.6.2:

如果有N个值位,则每个位应表示1和2 N -1之间的2的不同幂,因此该类型的对象应能够使用纯二进制表示来表示0到2 N-1的值; 这应该被称为价值表示。

如果符号位为零,则不会影响结果值。

如果整数类型中的任何位是1,整数整数是否表示非零? (如果这是“是”,则会对符号和幅度等一些表示进行额外限制)

不一定,实际上6.2.6.2中明确支持符号和幅度。

是否有保证的方法来检查是否有任何位未设置?

如果你不关心填充和符号位,你可以只比较0,但这不适用于1的补码表示(允许),因为所有位0和所有位1都表示值0。

否则:您可以通过unsigned char *读取每个字节的值,并将结果与​​0进行比较:

存储在无符号位域中的值和unsigned char类型的对象应使用纯二进制表示法表示

如果要检查特定位,可以使用(1u << n)构造合适的位掩码,但这不一定能让您检查符号位。

是否有保证的方法来检查是否设置了任何位?

答案基本上与上一个问题相同。

是否有保证的方法来设置最左边和/或最右边的位?

你的意思是最左边的价值点吗? 您可以根据类型对INT_MAX或UINT_MAX中的位数或等效值进行计数,并使用它来构造一个值(通过1 << n )来与原始值进行OR运算。

如果#1的答案是“否”,那么如何迭代整数类型的位并检查每个位是1还是0?

您可以使用重复移位的位掩码来执行此操作,但是您只能通过这种方式检查位而不是符号位。

对于bitmanipulations,你可以创建一个带有8个无符号位字段的结构,并让该结构的指针指向你的char。 通过这种方式,您可以轻松访问每个位。 但编译器可能会在掩盖下进行掩蔽,因此对于我认为的程序员来说,它只是一种更清晰的方式。 执行此操作时,您必须检查编译器是否不更改字段的顺序。

 yourstruct* pChar=(yourstruct*)(&c) pChar.Bit7=1; 

让我通过说我正在解决C和C ++(例如C90和更低版本,MS Visual C ++等)来解决这个问题:“最大的共同点”(与最新/最大的cx11“标准”相比)。

问:如果整数类型中的所有位都为零,整数整数是否代表零?

答:是的

问:如果整数类型中的任何位是1,那么整数整数是否表示非零? (如果这是“是”,则会对符号和幅度等一些表示进行额外限制)

答:是的。 这包括符号位,用于signed int。 我坦白地说不熟悉“量级”

问:是否有保证检查是否未设置任何位的方法?

答:“And’ing”总是保证了一个位掩码。

问:是否有保证检查是否设置了位的方法?

答:同样,“和”一个位掩码始终得到保证。

问:有保证的方法来设置最左边和/或最右边的位吗?

答:我相信您应该始终为所有实现/所有架构提供“MAX_INT”以确定最左边的位。

我准备好被焚烧……但我相信以上是准确的。 我希望它有所帮助。

恕我直言…