我有一个简短的问题. 如果我有一个像int x = 30;这样的变量

我知道,值30被更改为一个4字节的整数,然后它判断值30是否存储到整数变量中;如果是,则它起作用.

如果我有int x = 3.08;(它应该弹出一个错误),但3.08被更改为一个8字节的浮点数,那么它会判断该值是否存储在float中,但它希望存储在int中,所以它会弹出一个错误.

我的主要问题是:在将值放入变量之前,是否先将其解释为字节(位格式)?

推荐答案

我有一个简短的问题.如果我有像int x=30这样的变量;

我知道值30被转换为4字节的整数,然后它判断值30是否存储到整数变量中,如果是,则它工作.

通过"存储到整型变量",我想你的意思是编译器查看x的类型(这是一个int)和初始化器30的类型(这是一个int常量),并判断它们是否满足什么类型可以用来初始化什么类型的规则.

这是正确的;编译器确实分析了所涉及的类型.然而,假设初始化式是int,它不仅仅是判断被初始化的对象是不是int.C标准规定,任何算术类型都可以用于初始化任何算术类型.您甚至可以使用复数来初始化int,如int i = 3.0 + 4.0 * I;.

如果我的int x=3.08(应该会弹出一个错误),但3.08被改为8字节的浮点数,那么它会判断该值是否存储在浮点数中,但它想要存储在int中,所以它会弹出一个错误.

虽然C标准允许使用任何算术类型来初始化任何算术类型,但它也允许编译器对可能包含错误的代码发出警告,即使该代码是该标准允许的,并且其行为已由C标准完全定义.这里就是这种情况;int x = 3.08;不违反C标准中的约束,C标准也不需要任何诊断消息或错误,但编译器编写人员 Select 警告您,因为用double常量初始化int的代码可能是错误的,而不是故意 Select 的.

通常,这样的诊断消息可以通过提供给编译器的某个switch 来打开或关闭.此外,当编译器发出这样的消息时,通常有一种方法可以解决这一问题.例如,通过编写int x = (int) 3.08;,我们可以告诉编译器我们正在故意将double转换为int,然后它将不会生成该诊断消息.

我的主要问题是:在将值放入变量之前,是否先将其解释为字节(位格式)?

对于编译器如何执行其工作的这一方面,没有必要的顺序.它必须分析代码,如果C标准要求或由其设计者 Select ,它必须产生诊断消息,它必须将源代码中的常量转换为表示它们的字节(或以其他方式提供),并且它必须安排将这些字节存储在对象中以供其初始化.它可以按不同的顺序做这些事情.(请注意,这些操作可以通过优化进一步更改,这超出了本答案的范围.)

此外,编译器的设计比您目前所认为的更具概念性.有一个完整的类型分析系统,它既独立于编译器的其他方面,也与编译器的其他方面交织在一起,例如将常量转换为表示它们的字节.根据我对编译器设计的一般知识,我认为编译器的词法分析器最有可能读取3.08,将其转换为适当值的某种表示形式,并为编译器创建一个内部"标记",指示在源代码中的这一点上存在double常量.然后更高级别的代码分析在这一点上拥有double的后果是什么.

然而,完全有可能将编译器设计为使词法分析器读取3.08,创建指示其中存在double常量的标记,并将源文本"3.08"与该标记一起存储,并且编译器仅在对源代码进行进一步分析(包括判断类型规则)之后才将该"3.08"转换为浮点表示形式.

因此,编译器可以按任一顺序进行字节转换和类型判断.

C++相关问答推荐

理解C中的指针定义

为什么已经设置的值在C中被重置为for循环条件中的新值?

使用GOTO从多个嵌套循环C继续

C语言中的strstr问题

ATmega328P EEPROM未写入

Ruby C Api处理异常

正确的TCP/IP数据包 struct

为什么GDB/MI进程的FIFO循环中有read()阻塞

如何在c++中包装返回空*的函数

是否可以使用指针算法在不对齐的情况下在 struct 中相同类型的字段的连续序列之间移动?

为什么我会收到释放后堆使用错误?

解决S随机内存分配问题,实现跨进程高效数据共享

如何用c语言修改shadow文件hash部分(编程)?

Tic-tac-toe:从文件加载存储

如何在c中使用具有不同变量类型的内存分配?

Go和C中的数据 struct 对齐差异

RISC-V GCC编译器错误编译ASM代码

如何使用 raylib 显示数组中的图像

C23 中是否有 __attribute__((nonnull)) 的等效项?

int 与 size_t 与 long