-1L 1UL的清晰度

时间:2021-08-19 16:11:57

I have been reading the book The C Programming Language by K&R and came across this.

我一直在阅读K&R的“C语言程序设计语言”这本书。


Conversion rules are more complicated when unsigned operands are involved. The problem is that comparisons between signed and unsigned values are machine-dependent, because they depend on the sizes of the various integer types. For example, suppose that int is 16 bits and long is 32 bits. Then -1L < 1U, because 1U, which is an unsigned int, is promoted to a signed long. But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number.

涉及无符号操作数时,转换规则更复杂。问题是有符号值和无符号值之间的比较取决于机器,因为它们取决于各种整数类型的大小。例如,假设int是16位而long是32位。然后-1L <1U,因为1U是无符号整数,被提升为有符号长整数。但-1L> 1UL因为-1L被提升为无符号长,因此看起来是一个大的正数。


From my beginning of C, i have little difficult regarding this Unsigned and Signed values. Can any one Explain how an unsigned value converted to signed value and viceversa with an explample.

从我的C开始,我对这个无符号和有符号的值没什么困难。任何人都可以解释无符号值如何转换为有符号值,反之亦然。

2 个解决方案

#1


3  

You have touched the surface of usual arithmetic conversions with integral promotions (newer standards use term of integer promotions there).

您通过整体促销触及了常规算术转换的表面(较新的标准使用整数促销术语)。

What are these usual arithmetic conversions ?

In general when you have expression, that involves arithmetic or logical operator and operands don't match, then they need to be unified (as we say promoted) into common form. In C90 rules between integer operands (I am skipping intentionally rules for types "lower" that int here for simplicity) are in following gradation (note that there is no long long int type in C90):

通常,当你有表达式,涉及算术或逻辑运算符和操作数不匹配时,它们需要统一(如我们所说的提升)为通用形式。在整个操作数之间的C90规则中(为了简单起见,我跳过故意规则类型“低”,这里的int)是以下渐变(注意在C90中没有长long int类型):

intunsigned intlong intunsigned long int

int→unsigned int→long int→unsigned long int

However, there is one exception between unsigned int and long int. If these have the same size (in bits), then both operands of such types are promoted to common type unsigned long int. In any other case common type is that, which is on right side (e.g. when you have int and unsigned int operands, then first one is promoted to unsigned int). If both operands have the same type, then no promotion is made for types listed above.

但是,unsigned int和long int之间有一个例外。如果它们具有相同的大小(以位为单位),则这些类型的两个操作数都将提升为公共类型unsigned long int。在任何其他情况下,常见类型是在右侧(例如,当你有int和unsigned int操作数时,则第一个被提升为unsigned int)。如果两个操作数具有相同的类型,则不会对上面列出的类型进行升级。

How does this relate to -1L < 1U and -1L > 1UL ?

In your case it's assumed that sizeof(int) == 16 and sizeof(long) = 32, so for:

在你的情况下,假设sizeof(int)== 16和sizeof(long)= 32,所以对于:

  • -1L < 1U second operand is promoted to long int
  • -1L <1U秒操作数被提升为long int

  • -1L > 1UL first operand is promoted to unsigned long
  • -1L> 1UL第一个操作数被提升为无符号长整数

In former example value of expression is 1 as -1L < 1L. In latter case -1L is promoted to unsigned type by repeatedly adding or substracting n+1, when n is the largest value of type unsigned long (in your case n+1 == 2^32), which yields into large number (i.e. 2^32-1), thus value of whole expression is 1 (of type int) as well.

在前一示例中,表达式的值为1,为-1L <1L。在后一种情况下,当n是无符号long类型的最大值(在你的情况下为n + 1 == 2 ^ 32)时,-1L通过重复添加或减去n + 1被提升为无符号类型,这会产生大量数据(即2 ^ 32-1),因此整个表达式的值也是1(类型为int)。

#2


0  

Hum... there is a longer (detailed) answer, and a shorter (approximate) answer...

嗯......有一个更长(详细)的答案,还有一个较短的(近似的)答案......


...starting with the longer answer:

The standard (C99, 6.3.1) specifies an integer conversion rank, and where two integer operands have different rank, one will be converted up. The rank is related to the size of the integer; larger sizes have greater rank than smaller sizes. Where the sizes are the same there may be differences in rank -- but that's not important just now. However, a signed integer and an unsigned integer of the same size have the same rank.

标准(C99,6.3.1)指定整数转换等级,并且其中两个整数操作数具有不同的等级,一个将被转换。等级与整数的大小有关;较大的尺寸比较小尺寸具有更大的等级。在大小相同的情况下,排名可能会有所不同 - 但这一点并不重要。但是,有符号整数和相同大小的无符号整数具有相同的等级。

It's worth remembering that signed int and unsigned int have the same size, by definition. They are examples of what the standard calls corresponding integer types (C99, 6.2.5). Each signed integer type has a corresponding unsigned one, and vice versa -- except for _Bool which doesn't have a sign (and, FWIW, has the lowest rank). As above, corresponding signed and unsigned types have the same rank.

值得记住的是,根据定义,signed int和unsigned int具有相同的大小。它们是标准调用相应整数类型的示例(C99,6.2.5)。每个有符号整数类型都有一个相应的无符号整数类型,反之亦然 - 除了_Bool没有符号(和FWIW,具有最低等级)。如上所述,相应的有符号和无符号类型具有相同的等级。

C is very fond of int and unsigned int. It will promote integers of lesser rank to int (or to unsigned int, if the promoted integer is unsigned and the same size as int). This is called integer promotion (which is a subset of all the possible conversions). For many operators, C will perform integer promotion on both operands before doing anything else. It will also perform integer promotion on arguments for things like printf().

C非常喜欢int和unsigned int。它会将较小等级的整数提升为int(或者对于unsigned int,如果提升的整数是无符号的并且与int的大小相同)。这称为整数提升(它是所有可能转换的子集)。对于许多运算符,C将在执行任何其他操作之前对两个操作数执行整数提升。它还将对printf()之类的参数执行整数提升。

Now we get to what are known as the usual arithmetic conversions (C99, 6.3.1.8), which for two integer operands are:

现在我们进入所谓的通常算术转换(C99,6.3.1.8),它对于两个整数操作数是:

  1. both arguments are promoted as required, so will be at least int or unsigned int

    两个参数都按需要提升,因此至少是int或unsigned int

  2. if they are now not the same type (type, not rank):

    如果他们现在不是同一类型(类型,而不是排名):

    • if both types are signed, or both types are unsigned, the lower rank is converted to the higher.

      如果两种类型都是有符号的,或者两种类型都是无符号的,则较低的等级将转换为较高的等级。

      This is straightforward, and there is clearly no loss of signed-ness.

      这很简单,显然没有丢失签名。

    ...otherwise, for different types, of different signed-ness, size matters:

    ...否则,对于不同类型,不同的签名,大小问题:

    • if the signed operand has the greater size (and hence rank), the unsigned operand is converted to the type of the signed one.

      如果带符号的操作数具有更大的大小(因此具有排名),则无符号操作数将转换为已签名操作数的类型。

      This is also straightforward, the unsigned value can be represented, without loss, in the signed type.

      这也很简单,无符号值可以在签名类型中无损失地表示。

    • if the unsigned operand has the greater size (and hence rank), the signed operand is converted to the type of the unsigned one.

      如果无符号操作数具有更大的大小(因此具有排名),则将带符号的操作数转换为无符号操作数的类型。

      So, for (say) unsigned long long and int (which one assumes are different sizes), the int is converted up, by adding ULLONG_MAX + 1 to it.

      因此,对于(比方说)unsigned long long和int(假设它们的大小不同),通过向它添加ULLONG_MAX + 1来转换int。

      This is not so straightforward, the signed-ness is lost.

      这不是那么简单,失去了签名。

    ...otherwise, for different types, of different signed-ness, of the same size, the result will be two unsigned operands of their current size. The rank kicks in to decide what type the operands will be:

    ...否则,对于不同类型,具有相同大小的不同签名,结果将是其当前大小的两个无符号操作数。排名开始决定操作数的类型:

    • if the operands have the same rank, then the signed one is converted to the unsigned operand's type.

      如果操作数具有相同的排名,则签名的操作数将转换为无符号操作数的类型。

      This is what happens when you have int and unsigned int operands, the int is converted (by adding UINT_MAX + 1 to it).

      当你有int和unsigned int操作数时会发生这种情况,int被转换(通过向它添加UINT_MAX + 1)。

    • if the unsigned operand has the greater rank, then the signed operand is converted to the unsigned operand's type (as above).

      如果无符号操作数具有更大的等级,则将带符号的操作数转换为无符号操作数的类型(如上所述)。

    • otherwise, the signed operand has the greater rank, and both operands are converted to the unsigned type corresponding to the signed operand's type (ie to the unsigned type with the greater rank).

      否则,带符号的操作数具有更大的等级,并且两个操作数都被转换为对应于带符号操作数的类型的无符号类型(即,具有更高等级的无符号类型)。

This all looks terrifyingly complicated :-( But, keep in mind that the size of an integer is the major component of its rank -- what makes it look complicated dealing with integers of the same size, but different signedness and type.

这一切看起来都非常复杂:-(但是,请记住,整数的大小是其排名的主要组成部分 - 这使得它看起来很复杂,处理相同大小的整数,但签名和类型不同。

(For the picky: I have glossed over the wrinkle in the standard which allows for integer representations to include "padding" bits -- which is deeply exotic -- so, for size read width, where required.)

(对于挑剔:我已经掩盖了标准中的皱纹,允许整数表示包括“填充”位 - 这是非常奇特的 - 所以,对于尺寸读取宽度,在需要的地方。)


...but the essence of it is, in short:

After promotion to int or unsigned int:

升级到int或unsigned int后:

  1. if the operands have different sizes, the smaller is converted up, and if larger is unsigned but the smaller is not, the smaller loses its signed-ness.

    如果操作数具有不同的大小,则较小的转换为up,如果较大的是无符号但较小的则不转换,则较小的失去其签名。

  2. if the operands have the same size, but different signed-ness, the signed one is converted to unsigned, losing signed-ness.

    如果操作数具有相同的大小但签名不同,则签名的操作数将转换为无符号,失去签名。

The conversion to unsigned (the loss of signed-ness) requires the addition of MAX+1, where MAX is the maximum value of the unsigned type being converted to.

转换为无符号(丢失有符号)需要添加MAX + 1,其中MAX是转换为无符号类型的最大值。

Hence: -1L > 0UL... indeed -1L == ULONG_MAX.

因此:-1L> 0UL ...确实-1L == ULONG_MAX。

#1


3  

You have touched the surface of usual arithmetic conversions with integral promotions (newer standards use term of integer promotions there).

您通过整体促销触及了常规算术转换的表面(较新的标准使用整数促销术语)。

What are these usual arithmetic conversions ?

In general when you have expression, that involves arithmetic or logical operator and operands don't match, then they need to be unified (as we say promoted) into common form. In C90 rules between integer operands (I am skipping intentionally rules for types "lower" that int here for simplicity) are in following gradation (note that there is no long long int type in C90):

通常,当你有表达式,涉及算术或逻辑运算符和操作数不匹配时,它们需要统一(如我们所说的提升)为通用形式。在整个操作数之间的C90规则中(为了简单起见,我跳过故意规则类型“低”,这里的int)是以下渐变(注意在C90中没有长long int类型):

intunsigned intlong intunsigned long int

int→unsigned int→long int→unsigned long int

However, there is one exception between unsigned int and long int. If these have the same size (in bits), then both operands of such types are promoted to common type unsigned long int. In any other case common type is that, which is on right side (e.g. when you have int and unsigned int operands, then first one is promoted to unsigned int). If both operands have the same type, then no promotion is made for types listed above.

但是,unsigned int和long int之间有一个例外。如果它们具有相同的大小(以位为单位),则这些类型的两个操作数都将提升为公共类型unsigned long int。在任何其他情况下,常见类型是在右侧(例如,当你有int和unsigned int操作数时,则第一个被提升为unsigned int)。如果两个操作数具有相同的类型,则不会对上面列出的类型进行升级。

How does this relate to -1L < 1U and -1L > 1UL ?

In your case it's assumed that sizeof(int) == 16 and sizeof(long) = 32, so for:

在你的情况下,假设sizeof(int)== 16和sizeof(long)= 32,所以对于:

  • -1L < 1U second operand is promoted to long int
  • -1L <1U秒操作数被提升为long int

  • -1L > 1UL first operand is promoted to unsigned long
  • -1L> 1UL第一个操作数被提升为无符号长整数

In former example value of expression is 1 as -1L < 1L. In latter case -1L is promoted to unsigned type by repeatedly adding or substracting n+1, when n is the largest value of type unsigned long (in your case n+1 == 2^32), which yields into large number (i.e. 2^32-1), thus value of whole expression is 1 (of type int) as well.

在前一示例中,表达式的值为1,为-1L <1L。在后一种情况下,当n是无符号long类型的最大值(在你的情况下为n + 1 == 2 ^ 32)时,-1L通过重复添加或减去n + 1被提升为无符号类型,这会产生大量数据(即2 ^ 32-1),因此整个表达式的值也是1(类型为int)。

#2


0  

Hum... there is a longer (detailed) answer, and a shorter (approximate) answer...

嗯......有一个更长(详细)的答案,还有一个较短的(近似的)答案......


...starting with the longer answer:

The standard (C99, 6.3.1) specifies an integer conversion rank, and where two integer operands have different rank, one will be converted up. The rank is related to the size of the integer; larger sizes have greater rank than smaller sizes. Where the sizes are the same there may be differences in rank -- but that's not important just now. However, a signed integer and an unsigned integer of the same size have the same rank.

标准(C99,6.3.1)指定整数转换等级,并且其中两个整数操作数具有不同的等级,一个将被转换。等级与整数的大小有关;较大的尺寸比较小尺寸具有更大的等级。在大小相同的情况下,排名可能会有所不同 - 但这一点并不重要。但是,有符号整数和相同大小的无符号整数具有相同的等级。

It's worth remembering that signed int and unsigned int have the same size, by definition. They are examples of what the standard calls corresponding integer types (C99, 6.2.5). Each signed integer type has a corresponding unsigned one, and vice versa -- except for _Bool which doesn't have a sign (and, FWIW, has the lowest rank). As above, corresponding signed and unsigned types have the same rank.

值得记住的是,根据定义,signed int和unsigned int具有相同的大小。它们是标准调用相应整数类型的示例(C99,6.2.5)。每个有符号整数类型都有一个相应的无符号整数类型,反之亦然 - 除了_Bool没有符号(和FWIW,具有最低等级)。如上所述,相应的有符号和无符号类型具有相同的等级。

C is very fond of int and unsigned int. It will promote integers of lesser rank to int (or to unsigned int, if the promoted integer is unsigned and the same size as int). This is called integer promotion (which is a subset of all the possible conversions). For many operators, C will perform integer promotion on both operands before doing anything else. It will also perform integer promotion on arguments for things like printf().

C非常喜欢int和unsigned int。它会将较小等级的整数提升为int(或者对于unsigned int,如果提升的整数是无符号的并且与int的大小相同)。这称为整数提升(它是所有可能转换的子集)。对于许多运算符,C将在执行任何其他操作之前对两个操作数执行整数提升。它还将对printf()之类的参数执行整数提升。

Now we get to what are known as the usual arithmetic conversions (C99, 6.3.1.8), which for two integer operands are:

现在我们进入所谓的通常算术转换(C99,6.3.1.8),它对于两个整数操作数是:

  1. both arguments are promoted as required, so will be at least int or unsigned int

    两个参数都按需要提升,因此至少是int或unsigned int

  2. if they are now not the same type (type, not rank):

    如果他们现在不是同一类型(类型,而不是排名):

    • if both types are signed, or both types are unsigned, the lower rank is converted to the higher.

      如果两种类型都是有符号的,或者两种类型都是无符号的,则较低的等级将转换为较高的等级。

      This is straightforward, and there is clearly no loss of signed-ness.

      这很简单,显然没有丢失签名。

    ...otherwise, for different types, of different signed-ness, size matters:

    ...否则,对于不同类型,不同的签名,大小问题:

    • if the signed operand has the greater size (and hence rank), the unsigned operand is converted to the type of the signed one.

      如果带符号的操作数具有更大的大小(因此具有排名),则无符号操作数将转换为已签名操作数的类型。

      This is also straightforward, the unsigned value can be represented, without loss, in the signed type.

      这也很简单,无符号值可以在签名类型中无损失地表示。

    • if the unsigned operand has the greater size (and hence rank), the signed operand is converted to the type of the unsigned one.

      如果无符号操作数具有更大的大小(因此具有排名),则将带符号的操作数转换为无符号操作数的类型。

      So, for (say) unsigned long long and int (which one assumes are different sizes), the int is converted up, by adding ULLONG_MAX + 1 to it.

      因此,对于(比方说)unsigned long long和int(假设它们的大小不同),通过向它添加ULLONG_MAX + 1来转换int。

      This is not so straightforward, the signed-ness is lost.

      这不是那么简单,失去了签名。

    ...otherwise, for different types, of different signed-ness, of the same size, the result will be two unsigned operands of their current size. The rank kicks in to decide what type the operands will be:

    ...否则,对于不同类型,具有相同大小的不同签名,结果将是其当前大小的两个无符号操作数。排名开始决定操作数的类型:

    • if the operands have the same rank, then the signed one is converted to the unsigned operand's type.

      如果操作数具有相同的排名,则签名的操作数将转换为无符号操作数的类型。

      This is what happens when you have int and unsigned int operands, the int is converted (by adding UINT_MAX + 1 to it).

      当你有int和unsigned int操作数时会发生这种情况,int被转换(通过向它添加UINT_MAX + 1)。

    • if the unsigned operand has the greater rank, then the signed operand is converted to the unsigned operand's type (as above).

      如果无符号操作数具有更大的等级,则将带符号的操作数转换为无符号操作数的类型(如上所述)。

    • otherwise, the signed operand has the greater rank, and both operands are converted to the unsigned type corresponding to the signed operand's type (ie to the unsigned type with the greater rank).

      否则,带符号的操作数具有更大的等级,并且两个操作数都被转换为对应于带符号操作数的类型的无符号类型(即,具有更高等级的无符号类型)。

This all looks terrifyingly complicated :-( But, keep in mind that the size of an integer is the major component of its rank -- what makes it look complicated dealing with integers of the same size, but different signedness and type.

这一切看起来都非常复杂:-(但是,请记住,整数的大小是其排名的主要组成部分 - 这使得它看起来很复杂,处理相同大小的整数,但签名和类型不同。

(For the picky: I have glossed over the wrinkle in the standard which allows for integer representations to include "padding" bits -- which is deeply exotic -- so, for size read width, where required.)

(对于挑剔:我已经掩盖了标准中的皱纹,允许整数表示包括“填充”位 - 这是非常奇特的 - 所以,对于尺寸读取宽度,在需要的地方。)


...but the essence of it is, in short:

After promotion to int or unsigned int:

升级到int或unsigned int后:

  1. if the operands have different sizes, the smaller is converted up, and if larger is unsigned but the smaller is not, the smaller loses its signed-ness.

    如果操作数具有不同的大小,则较小的转换为up,如果较大的是无符号但较小的则不转换,则较小的失去其签名。

  2. if the operands have the same size, but different signed-ness, the signed one is converted to unsigned, losing signed-ness.

    如果操作数具有相同的大小但签名不同,则签名的操作数将转换为无符号,失去签名。

The conversion to unsigned (the loss of signed-ness) requires the addition of MAX+1, where MAX is the maximum value of the unsigned type being converted to.

转换为无符号(丢失有符号)需要添加MAX + 1,其中MAX是转换为无符号类型的最大值。

Hence: -1L > 0UL... indeed -1L == ULONG_MAX.

因此:-1L> 0UL ...确实-1L == ULONG_MAX。