【问题标题】:What's the meaning of "cast specifies a conversion"?“cast指定转换”是什么意思?
【发布时间】:2021-02-21 03:47:34
【问题描述】:

在 C 1999 注释 86 中,与 6.5.4 5 对话(我的粗体字)

如果表达式的值以比要求更高的精度或范围表示 由强制转换命名的类型 (6.3.1.8),然后 强制转换指定转换,即使 表达式的类型与命名类型相同。

signed char a = -2;
unsigned char b = 1;
b = (short)a + (short)b;

b = (short)a + (short)b;。这是一个例子

如果表达式的值以比要求更高的精度或范围表示 按强制转换命名的类型 (6.3.1.8),

因为如果没有强制转换,ab 都被提升为 int,它比由强制转换命名的类型 short 具有更高的精度或范围(假设 @987654327 @ 是 16 位,int 是 32 位)。

那么,在这种情况下,后一句

然后,即使表达式的类型与命名类型相同,强制转换也会指定转换。

我想知道这对b = (short)a + (short)b; 有何影响。

我的想法很简单。因为(cast) 的优先级高于加法+,所以首先ab(short) 强制转换,然后+ 的两个操作数通过通常的算术转换进行转换。但是“即使表达式的类型与命名类型相同,强制类型转换指定转换”这句话让我感到困惑。

【问题讨论】:

  • 粗体部分是像(double) 5.0 这样的转换,您将double5.0 转换为double
  • @Someprogrammerdude 但是5.0double 的类型是相同的,并且具有相同的精度和范围。你的意思是只有粗体部分固定?
  • "...即使表达式的类型..." (double) 5.0 的情况下的表达式是5.0。 “...与命名类型相同” (double) 5.0 中的“命名类型”为double。所以演员(double) 5.0是从doubledouble的转换。
  • (double) 5.0 是否满足“如果表达式的值是 ~ 通过强制转换 (6.3.1.8)”?我读了通常的算术转换。但是不知道为什么要指定6.3.1.8。
  • @Someprogrammerdude 抱歉之前的模棱两可的问题,我编辑了我的帖子以使事情变得清晰。如果您阅读我编辑的帖子,我将不胜感激。

标签: c language-lawyer c99 typecasting-operator


【解决方案1】:

这是关于浮点类型的。整数类型不受影响。

b = (短)a + (短)b;。这是“如果表达式的值以比要求更高的精度或范围表示...”的示例

不,该语句中的整数转换不是一个例子。 C 2018 6.3.1.8 2(与 C 1999 相同)告诉您它是关于浮点类型的:

浮动操作数的值和浮动表达式的结果可以用比类型要求更大的范围和精度来表示;类型不会因此而改变。

这里发生的情况是,根据 C 2018 5.2.4.2.2 10,C 标准允许以比名义类型更大的范围和精度计算浮点表达式:

除了赋值和强制转换(删除所有额外的范围和精度)之外,由具有浮动操作数的运算符产生的值和经过通常算术转换的值和浮动常量的值被评估为范围和精度可能更大的格式比类型要求的多……

(在 C 1999 中,类似的文本出现在 5.4.2.2.2 7。差异可能有一些意义,但这里不讨论。)

这意味着当您使用double 计算表达式时,编译器可能会生成使用long double 的代码。或者,当您使用float 计算表达式时,编译器可能会使用doublelong double。例如,这使得在具有加载和存储单精度 (float) 或双精度 (double) 浮点数据的指令但仅具有计算双精度指令的处理器上实现 C 变得更加容易-precision 浮点,不适用于单精度。

您从 C 1999 中引用的注释 86 已在 C 2018 中提升为规范性文本,如 6.5.4 6:

如果表达式的值表示的范围或精度大于强制转换命名的类型 (6.3.1.8) 所需的范围或精度,则强制转换指定转换,即使表达式的类型与命名的类型相同键入并删除任何额外的范围和精度。

这告诉你的是,演员表必须“消除”额外的范围和精度。 (这是不幸的措辞;最好是使用任何适用的舍入规则将值四舍五入为指定类型中可表示的值,通常是四舍五入到最接近的偶数。)

在 C 2018 6.3.1.5 1(C 1999 中不存在)中,关于浮点类型之间的转换,我们看到:

... 某些隐式转换的结果可能以比新类型所需的更大范围和精度表示(参见 6.3.1.8 和 6.8.6.4)。

所以情况是这样的:浮点表达式可以使用额外的范围和精度来计算。当存在隐式转换时,例如将float 乘以double(通常的算术转换将float 转换为double),这个额外的范围和精度可能会保留。但是,当您在源代码中进行强制转换时,必须执行“实际转换”,将具有额外精度的值转换为可在名义类型中表示的值。这就是转换指定转换的意思。

虽然赋值中的转换是隐式的,但执行此转换也需要赋值,正如我们在上面引用的 5.2.4.2.2 10 中所告知的那样。注释 65 至 6.3.1.8 2 中也提到了这一点:

仍然需要强制转换和赋值运算符来移除额外的范围和精度。

值得注意的是,return 语句执行隐式转换,但不需要删除额外的范围或精度。

【讨论】:

  • 感谢指出我的引用是关于浮动类型的,我误解了一些东西。结论是 1. 操作两个浮点操作数时,它们的表示范围更大(可能是 long double 或扩展 long double ) 2. 但是当您对两者之一使用类型转换时,它会四舍五入到转换类型的精度在计算过程中。对吗?
  • 你说我的引用不在规范部分。但是我提到的引用是在 6.5.4 的语义子条款中,而不是在脚注中。是否有每个人都在讨论的共同文档?我的 C99 草稿是this
  • @opol:该链接指向 n1256 草案的副本,该草案是 2007 年 9 月 7 日的委员会草案,直到 2011 年成为官方标准。它不是 1999 年的 C 标准,所以它不应被称为“C99”。您可以将其引用为草案 n1256。有关在哪里可以找到该标准的官方和非官方草案的信息,请参见 this answer
  • @opol:关于“它们以更大的范围表示”:它们可能以更大的范围和/或精度表示。这取决于实施。标头<float.h> 定义了一个宏FLT_EVAL_METHOD,其值可能会提供更多信息:如果为0,则所有浮点表达式都使用名义类型。如果是 1,floatdouble 使用 double。如果为 2,则所有浮点使用long double。如果它是 -1,则实现没有说明它做了什么。在某些情况下,它可能会使用额外的范围和/或精度,而在其他情况下则不会。
猜你喜欢
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多