3

在做了一些研究之后,我知道算术表达式 char 和 short 将在内部提升为 int。但我仍然想知道这样的整数提升是否会在内部分配中发生。

(所以请不要只给我关于其他表达式的链接。我问的是 ASSIGNMENT 表达式内部发生了什么)

char ch1, ch2 = -1;
ch1 = ch2;  // Q

问:以下哪项会在内部发生?

1、ch1的值直接赋给ch2。整数促销不会在这里发生。

2、ch1的值先升为int型(8位→32位),再将32位的值降为char型,8位,最终结果。整数促销发生在这里。

我找到了这本书:C Primer Plus,在第 174 页有:

“...当出现在表达式中时,char 和 short,无论有符号还是无符号,都会自动转换为 int,或者如果需要,转换为 unsigned int...”

所以我认为它应该是 2,但我听说有人告诉我它应该是 1,整数提升不会发生。

我真的很困惑。请问你能帮帮我吗?先感谢您。

4

4 回答 4

3

来自 C99 标准:

6.5.16.1 简单赋值

2 在简单赋值(=)中,右操作数的值被转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。

在您的情况下,由于 LHS 和 RHS 都属于同一类型,因此无需进行任何转换。

于 2015-10-26T03:55:12.533 回答
2

答案既不是 1 也不是 2。

ch2 的值直接赋值给 ch1。对于赋值运算符,左侧操作数是目标。

没有促销活动;该行为由 C11 6.5.16.1/2 指定:

在简单赋值 ( =) 中,右操作数的值被转换为赋值表达式的类型,并替换存储在左操作数指定的对象中的值。

在上一段中,它定义为:

赋值表达式的类型是左操作数在左值转换后的类型。

其中“左值转换”是指左值到右值的转换,它具有删除类型的const,volatile_Atomic限定符的效果。(它也对数组类型有影响,但这里没有实际意义,因为数组不能作为赋值的左操作数出现)。

您对“C Primer Plus”的引用是本书的错误。并非所有表达式都出现整数提升。事实上,它们发生在整数是运算符的操作数时,并且该运算符的定义指定其操作数经历整数提升。

大多数运算符都指定了这一点,但赋值运算符,sizeof例如,没有。您可以检查每个运算符的 C 标准规范,以查看该运算符是否提升其操作数。

于 2015-10-26T05:39:17.897 回答
1

正如@chux 的评论所说,我不明白这是一个问题。由于一切都发生在内部,因此您应该将其视为黑匣子,而不应依赖此类行为。

但是,出于好奇,我拿走了代码片段并将其编译为程序集。让我们看看到底发生了什么!

这是源 C 代码。我将它保存在一个名为test.c

int main() {
  char ch1 = -1;
  char ch2 = -1;
  ch1 = ch2;
}

这是 gcc 生成的程序集。您可以通过调用自己生成它gcc -S test.c。以下是相关部分:

...

    movb    $-1, -1(%rbp)
    movb    $-1, -2(%rbp)
    movb    -2(%rbp), %cl
    movb    %cl, -1(%rbp)
    popq    %rbp

...

所以基本上,我们将值 -1 两次压入堆栈 ( %rbp),然后将存储在第二个插槽 ( ch2) 中的值移动到另一个临时寄存器%cl,最后将其分配给第一个插槽ch1

等等,这个临时注册业务是什么?!事实证明,它%cl 的大小正好是一个字节!所以是的,没有转换发生。

顺便说一句:就汇编而言,没有类型转换之类的东西,除非我们没有足够的空间来存储一个。例如,如果我们将值从 -1 更改为 65537(刚好超过 short),那么我们看到的是:

x = 65537;

变成:

movl    $65537, -4(%rbp)

我们只是在堆栈上为变量 x 分配 4 个字节。所以在内部,提升只是在堆栈上分配更多空间。当您将整数降级为 char 时,我们只是从整数中取出最后一个字节并将其粘贴到堆栈上的新插槽中。因此,如果两者都是以字符开头(两者都在堆栈上分配了一个字节槽),则实际上不需要进行转换。但当然,这取决于编译器。你可以有一个非常低效的编译器,它实际上ch2以 1 MB 的大小推送到堆栈,计算 的阶乘ch1,唱一首歌,然后ch1用赋值ch2。正如我一开始所说,你应该把它当作一个黑匣子,而不是指望它!

于 2015-10-26T03:52:28.630 回答
0

默认情况下,char 的类型是有符号的。所以 ch2=-1 是一个有效值。所以不需要整数提升。

仅当混合 2 种不同类型时才会发生整数提升。用于计算的结果类型是 2 种类型中较大的类型。对于 char 到整数的提升,正如您在 2 中提到的那样。第一次整数提升发生在计算中,并且在存储时,值被截断为实际的存储桶大小。

于 2015-10-26T03:40:35.167 回答