在 C 中赋值之前如何存储表达式值?

How are expression values stored before they become assigned in C?

这里是初学者问题; 在 C 语言中,当您将数值赋给变量时,语言明确表示该变量具有特定类型,该类型只能包含特定范围的数值。如果分配给变量的值超出其类型定义的范围,它将溢出。例子;

char foo = 1000;

这里 foo 预计不等于 1000。我想赋值涉及将表达式的值转换为变量类型,因此,赋值可能会根据是否溢出来修改表达式的值发生与否,取决于变量类型和表达式的值。在更复杂的情况下(不是硬编码值),我想在分配实际发生之前不知道将存储在内存中的值。

我的问题是;在代码执行期间,表达式的值在赋值之前如何存储?

事实上,它们必须写在一定数量的位上,这给了它们一个最小值、一个最大值和一个浮点值的最大精度。

作为本题的应用;是否可以编写一个涉及硬编码数字的表达式,该数字太大以至于在执行期间实际上无法正确存储?想象一个硬编码表达式涉及一个比最大可能值稍大的数字除以二,这样表达式理论上会产生一个可表示的数字,但它不会。

My question is; during code execution, how are the values of expressions stored before they are assigned?

通常,它们在代码中存储为常量,如下所示:

movb   $-0x18, -0x11(%rbp)

-0x18 是存储在某个内存位置的常量 -24。

I suppose assignment involves the expression's value to be casted to the variable type, consequently, assignment would potentially modify the value of the expression

没错。我的编译器警告我:Implicit conversion from 'int' to 'char' changes value from 1000 to -24

As an application of this question; is it possible to write an expression involving a hardcoded number so big that it actually cannot be stored properly during execution?

编译器通常会简化常量表达式,因此如果您有一个包含数字的表达式,该数字足够小以至于编译器可以使用它,但又太大而无法存储到您尝试使用的任何类型中,那么是的,编译器会做正确的事情。如果我将您的示例更改为:

char foo = 1000/8;

来自我的编译器的警告消失了。

通常,C 中的每个表达式,包括另一个表达式中的子表达式,都有一个类型。对于标识符,声明了类型。对于常量或文字,类型是常量或文字的形式和值的结果。对于运算符的结果,类型由操作数的类型和运算符的规则决定。

例如对于整数常量,在C 2018 6.4.4.1 5中有一个table。对于没有后缀的十进制常量(如l代表long),它表示该类型是 intlong intlong long int 中第一个可以表示该值的类型。下一段还说,如果该值不适合其中任何一个,它可以适合 C 实现提供的某些扩展整数类型。它还表示如果该值不能由其列表中的任何类型表示,并且它“没​​有类型”。如果常量没有类型,则程序违反了约束条款 6.4.4 2 中的约束,即“每个常量应具有类型……”,并且 C 标准未定义该行为。当程序违反约束子句中列出的约束时,编译器必须为此生成诊断消息。

对于许多运算符,规则规定整数操作数被提升到至少 int 的宽度。 (我在这里省略了一些技术细节,但这是整数提升的主要效果。)这意味着你不能在 上做算术只是 a charshort value 在 C 实现中,这些类型比 int 窄。此外,对于许多具有两个操作数的运算符,操作数被转换为一些常见类型,通常是“更大”的类型(尽管也有一些技术细节,由于有符号和无符号类型之间的转换,这可能会更麻烦)。

所有这些关于类型的规则都会影响表达式求值的。如果将 X 类型的值与 Y 类型的值相加,然后乘以 Z[=34] 类型的值=],将应用规则来确定结果的值。但是规则没有说明当程序使用表达式时必须如何表示值。编译器可能会生成处理寄存器中的值的代码,在指令的直接字段中保留一些常量,在程序执行期间动态构建一些常量,不包含执行显式操作的实际指令,因为编译器将表达式优化为不同的形式,等等。 C 标准仅要求在将值存储在对象中时以某种方式表示该值(保留用于保存值的内存,与变量的定义一样)。 (甚至可以通过优化删除,只要程序在 C 标准定义的可观察效果方面表现相同。)