4

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

情况1

 int i=999;
 char c=i;

案例2

 char c=999;

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

编辑

这是我正在谈论的链接

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

一位在那里发表评论的成员说——这不是一回事。第一个是赋值,第二个是初始化

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

4

5 回答 5

8

它们具有相同的语义。

常量999的类型为int

int i=999;
char c=i;

i创建为 type 的对象并使用value进行int初始化,具有明显的语义。int999

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

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

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

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

char c=999;

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

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

在第二种情况下,您可能更有可能收到警告,因为它正在转换常量表达式;在第一种情况下,编译器可能不会跟踪i. 但是一个足够聪明的编译器可以对两者都发出警告,而一个足够幼稚(但仍然完全符合)的编译器则不能对两者都发出警告。

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

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

于 2013-05-11T18:06:42.093 回答
2

在这两种情况下,任何优化编译器只会使 inti = 999局部变量消失并直接将截断的值分配给c。(假设您没有i在其他任何地方使用)

于 2013-05-11T17:49:00.240 回答
1

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

于 2013-05-11T17:48:58.597 回答
1

除了第一个也定义了itype的对象之外int,语义是相同的。

于 2013-05-11T18:03:45.200 回答
0

我,实际上是 999

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

于 2013-05-11T18:05:16.340 回答