怎么样{int i = 999; char c = i;}与{char c = 999;}不同?

我的朋友说他在某些页面上看到它们是不同的,但两者怎么可能不同呢?

情况1

int i=999; char c=i; 

案例2

  char c=999; 

在第一种情况下,我们将整数i初始化为999 ,然后用i初始化c ,实际上是999在第二种情况下,我们用999直接初始化c 。除了信息的截断和丢失,这些是怎么回事两种情况不同?

编辑

这是我正在谈论的链接

为什么在将int转换为char时没有溢出警告

一位评论的成员说 – 这不是一回事。 第一个是赋值,第二个是初始化

那么这不仅仅是编译器的优化问题吗?

它们具有相同的语义。

常量999的类型为int

 int i=999; char c=i; 

i创建了int类型的对象,并使用int999初始化,具有明显的语义。

c被创建为char类型的对象,并使用i的值初始化,恰好是999 。 该值隐式地从int转换为char

plain char的签名是实现定义的。

如果plain char是无符号类型,则转换结果已明确定义。 该值以模数CHAR_MAX+1减少。 对于具有8位字节( CHAR_BIT==8 )的典型实现, CHAR_MAX+1将为256,并且存储的值将为999 % 256231

如果plain char是有符号类型,并且999超过CHAR_MAX ,则转换产生实现定义的结果(或者,从C99开始,引发实现定义的信号,但我知道没有实现这样做的实现)。 通常 ,对于CHAR_BIT==8的二进制补码系统,结果为-25

 char c=999; 

c被创建为char类型的对象。 它的初始值是转换为charint999 – 与我上面描述的完全相同的规则。

如果CHAR_MAX >= 999 (仅当CHAR_BIT ,一个字节中的位数至少为10时才会发生),那么转换是微不足道的。 有一些用于DSP(数字信号处理器)的C实现,其中CHAR_BIT设置为,例如,32。在大多数系统上,这不是你可能遇到的问题。

你可能更有可能在第二种情况下得到警告,因为它正在转换一个常量表达式; 在第一种情况下,编译器可能无法跟踪i的预期值。 但是一个足够聪明的编译器可以警告两者,并且一个足够幼稚(但仍然完全符合)的编译器可以警告两者。

如上所述,当源值不适合目标类型时,将值转换为有符号类型的结果是实现定义的。 我想可以想象一个实现可以为常量和非常量表达式定义不同的规则。 不过,那将是一个不正当的选择; 我不确定DS9K是否能做到这一点。

至于引用的注释“第一个是赋值,第二个是初始化”,这是不正确的。 两者都是初始化; 两个代码段中都没有赋值。 不同之处在于,一个是具有常量值的初始化,而另一个不是。 顺便说一句,这意味着第二个片段可能出现在任何函数之外的文件范围内,而第一个片段则不能。

任何优化编译器都会使int i = 999局部变量消失,并在两种情况下将截断值直接赋值给c 。 (假设你没有在其他任何地方使用i

这取决于您的编译器和优化设置。 看看实际的assembly清单,看看它们有多么不同。 对于GCC和合理的优化,这两个代码块可能是等价的。

除了第一个还定义类型为int的对象i ,语义是相同的。

我,实际上是999

不, i是一个变量。 从语义上讲,它在c初始化时没有值……直到运行时才会知道该值(即使我们可以清楚地看到它将是什么,并且优化编译器也是如此)。 但是在第2种情况下,你将999分配给一个不适合的字符,因此编译器会发出警告。