char 和 short 在赋值表达式中被降级之前会被提升为 int 吗?
Will char and short be promoted to int before being demoted in assignment expressions?
经过一些研究,我知道在算术表达式中 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,其中不会发生整数提升。
我真的很困惑。请问你能帮帮我吗?
提前谢谢你。
默认情况下,char 类型是有符号的。所以 ch2=-1 是一个有效值。所以不需要整数提升。
仅当混合使用 2 种不同类型时才会进行整数提升。用于计算的结果类型是两种类型中较大的一种。
对于 char 到整数提升,正如您在 2 中提到的那样。第一个整数提升发生在计算和存储时间
这些值被截断为实际存储桶大小。
正如@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
is exactly one byte in size!所以是的,没有发生转换。
顺便说一句:在汇编中,没有类型转换这样的东西,除非我们没有足够的 space 来存储一个。例如,如果我们将值从 -1 更改为 65537(刚好超过 short),那么我们看到的是:
x = 65537;
变为:
movl 537, -4(%rbp)
我们只是在堆栈上为变量 x 分配了 4 个字节。所以在内部,提升只是在堆栈上分配更多 space。当您将整数降级为 char 时,我们只是从整数中取出最后一个字节并将其粘贴到堆栈上的新插槽中。因此,如果两者都是以字符开头(都在堆栈上分配了一个字节槽),则实际上不需要进行转换。但是,当然,这取决于编译器。你可以有一个非常低效的编译器,它实际上将 ch2
推入大小为 1 MB 的堆栈,计算 ch1
的阶乘,唱一首歌,然后将 ch1
分配给 ch2
。正如我一开始所说,你应该把它当作一个黑盒子,不要指望它!
来自 C99 标准:
6.5.16.1 简单赋值
2 In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
在你的情况下,因为LHS和RHS是同一类型,所以不需要任何转换。
答案既不是 1 也不是 2。
ch2的值直接赋值给ch1。使用赋值运算符,左侧操作数是目标。
没有促销活动;该行为由 C11 6.5.16.1/2:
指定
In simple assignment (=
), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
在上一段中定义:
The type of an assignment expression is the type the left operand would have
after lvalue conversion.
其中 "lvalue conversion" 表示左值到右值的转换,其作用是删除类型的 const
、volatile
和 _Atomic
限定符。 (它对数组类型也有影响,但这里没有实际意义,因为数组不能作为赋值的左操作数出现)。
您引用 "C Primer Plus" 的内容是书中的错误。整数提升不会出现在所有表达式中。事实上,当整数是运算符的操作数时,它们就会出现,并且该运算符的定义指定其操作数进行整数提升。
大多数运算符都指定了这一点,但赋值运算符,例如 sizeof
,则没有。您可以检查每个运算符的 C 标准规范,以查看该运算符是否提升其操作数。
经过一些研究,我知道在算术表达式中 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,其中不会发生整数提升。
我真的很困惑。请问你能帮帮我吗? 提前谢谢你。
默认情况下,char 类型是有符号的。所以 ch2=-1 是一个有效值。所以不需要整数提升。
仅当混合使用 2 种不同类型时才会进行整数提升。用于计算的结果类型是两种类型中较大的一种。 对于 char 到整数提升,正如您在 2 中提到的那样。第一个整数提升发生在计算和存储时间 这些值被截断为实际存储桶大小。
正如@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
is exactly one byte in size!所以是的,没有发生转换。
顺便说一句:在汇编中,没有类型转换这样的东西,除非我们没有足够的 space 来存储一个。例如,如果我们将值从 -1 更改为 65537(刚好超过 short),那么我们看到的是:
x = 65537;
变为:
movl 537, -4(%rbp)
我们只是在堆栈上为变量 x 分配了 4 个字节。所以在内部,提升只是在堆栈上分配更多 space。当您将整数降级为 char 时,我们只是从整数中取出最后一个字节并将其粘贴到堆栈上的新插槽中。因此,如果两者都是以字符开头(都在堆栈上分配了一个字节槽),则实际上不需要进行转换。但是,当然,这取决于编译器。你可以有一个非常低效的编译器,它实际上将 ch2
推入大小为 1 MB 的堆栈,计算 ch1
的阶乘,唱一首歌,然后将 ch1
分配给 ch2
。正如我一开始所说,你应该把它当作一个黑盒子,不要指望它!
来自 C99 标准:
6.5.16.1 简单赋值
2 In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
在你的情况下,因为LHS和RHS是同一类型,所以不需要任何转换。
答案既不是 1 也不是 2。
ch2的值直接赋值给ch1。使用赋值运算符,左侧操作数是目标。
没有促销活动;该行为由 C11 6.5.16.1/2:
指定In simple assignment (
=
), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.
在上一段中定义:
The type of an assignment expression is the type the left operand would have after lvalue conversion.
其中 "lvalue conversion" 表示左值到右值的转换,其作用是删除类型的 const
、volatile
和 _Atomic
限定符。 (它对数组类型也有影响,但这里没有实际意义,因为数组不能作为赋值的左操作数出现)。
您引用 "C Primer Plus" 的内容是书中的错误。整数提升不会出现在所有表达式中。事实上,当整数是运算符的操作数时,它们就会出现,并且该运算符的定义指定其操作数进行整数提升。
大多数运算符都指定了这一点,但赋值运算符,例如 sizeof
,则没有。您可以检查每个运算符的 C 标准规范,以查看该运算符是否提升其操作数。