如果在移位运算符中使用了强制类型转换操作符。

huangapple go评论72阅读模式
英文:

What if a cast operator is used in shift operators

问题

《JLS》中指出:

> 移位表达式的类型是左操作数的提升类型。
>
> 如果左操作数的提升类型是int,则只使用右操作数的最低五位作为移位距离。就像右操作数已经被位逻辑与运算符 & (§15.22.1) 与掩码值0x1f (0b11111) 进行了运算。因此,实际使用的移位距离总是在0到31的范围内。
>
> 如果左操作数的提升类型是long,则只使用右操作数的最低六位作为移位距离。就像右操作数已经被位逻辑与运算符 & (§15.22.1) 与掩码值0x3f (0b111111) 进行了运算。因此,实际使用的移位距离总是在0到63的范围内。

因此,如果我使用强制类型转换操作符显式地创建一个字节和一个短整数操作数,如(byte)100<<100(short)100<<100,右操作数的可用位是多少?

编辑:如果操作数已经使用类型转换运算符转换为不同(较小)的类型,那么操作数是否会经历数值提升(一元/二元)?如果是这种情况,你如何解释表达式具有字节变量b1 = (byte)(b2 + b3),因为在强制转换转换后,字节结果可能会按照数值提升转换为int?

英文:

The JLS says that

> The type of the shift expression is the promoted type of the left-hand
> operand.
>
> If the promoted type of the left-hand operand is int, then only the
> five lowest-order bits of the right-hand operand are used as the shift
> distance. It is as if the right-hand operand were subjected to a
> bitwise logical AND operator & (§15.22.1) with the mask value 0x1f
> (0b11111). The shift distance actually used is therefore always in the
> range 0 to 31, inclusive.
>
> If the promoted type of the left-hand operand is long, then only the
> six lowest-order bits of the right-hand operand are used as the shift
> distance. It is as if the right-hand operand were subjected to a
> bitwise logical AND operator & (§15.22.1) with the mask value 0x3f
> (0b111111). The shift distance actually used is therefore always in
> the range 0 to 63, inclusive.

So if I explicitly make a byte and a short operand using the cast operator like (byte)100<<100 and (short)100<<100, what will be the usable bits of the right operand?

Edit: Does an operand undergo a numeric promotion (unary/binary) if it has already been converted to a different (smaller) type using a casting operator? If this is the case, how would you explain the expression having byte variables b1 = (byte)(b2 + b3) because after the cast conversion, the byte result will probably convert to int as per the numeric promotion?

答案1

得分: 2

以下是翻译好的部分:

Java 8 JLS 也在 §5.6.1 中指出:

5.6.1. 一元数值提升

一些操作符对单个操作数应用一元数值提升,该操作数必须产生数值类型的值:

...

  • 否则,如果操作数的编译时类型为 byteshortchar,则通过扩展基本转换(§5.1.2)将其提升为 int 类型的值。

...

因此,如果我们考虑以下表达式:

int i = ...
short s = (short) i << 2;

将会导致编译器错误:

Main.java:4: 错误: 不兼容的类型: 从 int 转换到 short 可能会丢失精度
short s = (short) i << 2;

这是因为转换与移位操作的第一个参数绑定在一起,而不是整个表达式。以下是带有显式括号的整个表达式:

short s = ((byte) i) << 2;

然而,

int i = ...;
int j = (short) i << 2;

将会成功编译。

因此,对于任何小于 int 的值,有效位数与 int 相同(5 位),因为它们会自动向上转型为 int

如果你将整个表达式的结果进行类型转换,例如 shortshort s = (short) (i << 2)),则编译器不会自动进行操作。但是,Bohemian 的回答 对于在类型转换后右操作数的哪些位会影响值提供了逻辑上的限制。


在更新的 JLS 版本中,该部分已经被重新措辞。例如,在 Java 14 JLS,§5.6 中,我们可以找到以下内容(为了简洁起见,我建议阅读整个段落以获取完整的上下文):

5.6. 数值上下文

数值上下文适用于算术操作符的操作数、数组的创建和访问表达式、条件表达式以及 switch 表达式的结果表达式。

如果表达式满足以下条件之一,则表达式出现在数值算术上下文中:

...

  • 移位操作符 <<>>>>>(§15.19)的操作数。这些移位操作符的操作数被单独处理,而不是作为一组处理。长整型的移位距离(右操作数)不会将被移位的值(左操作数)提升为长整型。

...

数值提升确定数值上下文中所有表达式的提升类型。所选择的提升类型使得每个表达式都可以转换为提升类型,并且对于算术操作,操作在提升类型的值上是有定义的。对于数值上下文中的表达式,表达式的顺序对于数值提升来说并不重要。规则如下:

...

  1. 接下来,根据以下规则,将宽化基本转换(§5.1.2)和缩窄基本转换(§5.1.3)应用于某些表达式:

    ...

    • 否则,没有任何表达式是 doublefloatlong 类型。在这种情况下,上下文的类型确定了如何选择提升类型。

      在数值算术上下文或数值数组上下文中,提升类型为 int,并且所有不是 int 类型的表达式都会被宽化基本转换为 int

      在数值选择上下文中,应用以下规则:

      ...

      • 否则,提升类型为 int,并且所有不是 int 类型的表达式都会被宽化基本转换为 int

      ...

英文:

The Java 8 JLS also states in §5.6.1:

> 5.6.1. Unary Numeric Promotion
>
> Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:
>
> ...
>
> - Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).
>
> ...

Thus, if we take the following expression:

int i = ...
short s = (short) i &lt;&lt; 2;

Will result in a compiler error:

Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i &lt;&lt; 2;

<kbd>Ideone demo</kbd>

This is due to the fact that the cast binds to the first argument of the shift, not the whole expression. Here is the whole expression with explicit parenthesis:

short s = ((byte) i) &lt;&lt; 2;

Whereas

int i = ...;
int j = (short) i &lt;&lt; 2;

Will successfully compile.

<kbd>Ideone demo</kbd>

So the effective bits to use for anything &lt; int is the same as for int (5 bits) since they are upcasted to int automatically.

If you cast the result of the whole expression to, e.g. short (short s = (short) (i &lt;&lt; 2), then there is no automatism that takes place in the compiler. But Bohemian's answer gives a logical bound as to what bits of the right hand operator will effectively influence the value after the cast.


In newer JLS versions, the section has been reworded. For example, in Java 14 JLS, §5.6 we find (the section is shortened for breviety, I recommend reading the whole paragraph to get the full context):

> 5.6. Numeric Contexts
>
> Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions of switch expressions.
>
> An expression appears in a numeric arithmetic context if the expression is one of the following:
>
> ...
>
> - An operand of a shift operator &lt;&lt;, &gt;&gt;, or &gt;&gt;&gt; (§15.19). Operands of these shift operators are treated separately rather than as a group. A long shift distance (right operand) does not promote the value being shifted (left operand) to long.
>
> ...
>
> Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:
>
> ...
>
> 2. Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
>
> ...
>
> - Otherwise, none of the expressions are of type double, float, or long. In this case, the kind of context determines how the promoted type is chosen.
>
> In a numeric arithmetic context or a numeric array context, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
>
> In a numeric choice context, the following rules apply:
>
> ...
>
> - Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.
>
> ...

答案2

得分: 0

最大可用移位距离的位数由log2n给出,其中n是用于表示左手类型的值的位数。

byte有8位。log28为3。因此,只使用最右边的3位,从而在范围0-7内给出移位值。

short有16位。log216为4。因此,只使用最右边的4位,从而在范围0-15内给出移位值。

英文:

The number of bits of the maximum usable shift distance is given by log<sub>2</sub>n, where n is the number of bits used to represent values of the left hand type.

byte has 8 bits. log<sub>2</sub>8 is 3. So only the right most 3 bits are used, giving a shift value in the range 0-7.

short has 16 bits. log<sub>2</sub>16 is 4. So only the right most 4 bits are used, giving a shift value in the range 0-15.

huangapple
  • 本文由 发表于 2020年8月19日 03:05:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63475130.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定