<大厂面试高频考点>程序环境和预处理

简介: <大厂面试高频考点>程序环境和预处理

一.程序的翻译环境和执行环境


概念介绍:

在ANSI C的任何一种实现中,都会存在两个环境。

1.翻译环境:将源代码转换成可执行的机器指令。(编译器)

2.执行环境: 实际执行代码。(操作系统)

二.详解翻译环境


即:一个源程序文件怎么转化成一个可执行程序的。

流程:多个源文件单独经过编译器处理,再经过链接器链接,最后形成一个可执行程序。

1.编译

(1)预编译(文本操作)

文本操作:文件的替换调用

a.头文件的包含

#include — 预处理指令

b.#define定义符号的替换

#define —预处理指令

c.删除注释

(2)编译(把C语言代码翻译成汇编代码)

a.语法分析

b.词法分析

c.语义分析

d.符号汇总:只汇总全局符号 例如:Add main(链接时会用到)

(3)汇编(汇编指令翻译成二进制指令)

a.形成符号表:每个源文件都是单独编译,都形成自己的符号表(包括引用的外部符号),并带有符号地址,如果是外部符号就赋一个无意义的地址

(4)链接(把多个经过编译的源文件+链接库 链接)

a.合并段表:把不同源文件的相同段进行合并

b.符号表的合并和重定位:把不同源文件形成的符号表合并,使得外部声明的符号得到其真正的地址(所以如果未定义,会在链接的时候报错:无法解析的外部符号)

三.概述运行环境


程序执行的过程

1.程序必须载入内存中。在有操作系统的环境中,载入由操作系统完成。在独立的环境中,载入到内存必须由手工安排。


2.程序的执行开始。调用main函数。


3.开始执行代码。这个时候程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。同时也就可以使用静态内存。


4.终止程序。正常终止main,也可能是异常终止。

四.预处理详解


1.预定义符号

a.__FILE__         进行编译的源文件


b.__LINE__         文件当前的行号


c.__DATE__        文件被编译的日期


d.__TIME__         文件被编译的时间


e.__STDC__        如果编译器遵循ANSI C ,其值为1,否则未定义

2.#define

(1)#define定义标识符

非常灵活,在末尾不要加;会出问题


因为宏定义是直接替换的,所以由于运算符优先级的不同,会导致一些问题。

(2)#define定义的宏

所以我们在进行宏定义的时候,要把变量都加上括号、把宏的整体也加上括号。


注意:宏参数和#define定义中可以出现其他#define定义的符号。但是宏不能递归。


          字符串中出现宏定义符号 不会被替换


          #undef NAME  这条指令用于移除一个宏定义

3.#和##

(1)# 将参数插入到字符串中

铺垫:由于C语言对于字符串的打印有一个会合并的特点。(两个打印出来效果一样)

所以

我们用宏可以实现如下效果:

演示1:

#include<stdio.h>
#define PRINT(N) printf("the value of "#N" is %d\n",N)  //无分号!
int main()
{
  int a = 10;
  PRINT(a);
  int b = 20;
  PRINT(b);
}

演示2:

#include<stdio.h>
#define PRINT(N,format) printf("the value of "#N" is "#format"\n",N)  //无分号!
int main()
{
  int a = 10;
  PRINT(a,%d);
  double b = 3.14;
  PRINT(b,%lf);
}

(2)## 可以把它两边的符号合成一个符号

其允许从分离的片段中创建标识符

演示:

#include<stdio.h>
#define CAT(name,num) name##num
int main()
{
  int class105 = 105;
  printf("%d\n", CAT(class, 105));
}

4.带有副作用的宏参数

b=a+1; 不带副作用

b=a++; 带有副作用 改变了a的值 宏替换是自左向右一步一步替换的,此时a的值已经发生改变

演示:

#include<stdio.h>
#define MAX(x,y) ((x)>(y)?(x):(y))
int main()
{
  int a = 5;
  int b = 8;
  int c = MAX(a++, b++);
  printf("%d %d %d", a, b, c);
}

5.宏和函数的对比

6.命令行定义(在编译的过程中定义符号)

当我们根据同一个源文件编译出不同版本可用命令行定义,例如:可以用来调整数组大小。

7.条件编译

(1)#if

#if 常量表达式  如果为真 进入编译

......


#endif  结束编译


(2)多个分支的条件编译

#if 常量表达式


...


#elif 常量表达式


...


#endif


(3) 判断是否被定义

a.如果定义了 就为真 参与编译


#if defined(NAME)


...


#endif

#ifdef NAME

...

#endif

b.如果没定义  参与编译

#if !defined(NAME)

...

#endif

#ifndef NAME

...

#endif

(4)嵌套指令

与if语句嵌套相同,不过每组条件编译语句都要用#endif来结束

8.文件包含

(1)头文件被包含的方式

a.本地文件包含


#include "filename"


查找策略:两步走:先在源文件所在目录下查找,如果未找到,就像查找库函数头文件一样在标准位置查找头文件。


b.库函数包含


#include


查找策略:直接去标准路径下查找


(2)防止重复包含

a.


#ifndef __NAME_H__   (名字随便写 它只是判断这条语句之前有没有走过)


#define __NAME_H__


.......


#endif


b.


#pragma once


目录
相关文章
|
1月前
|
Java 程序员
面试高频考点!关于构造方法的那些事儿
本文介绍了Java中的构造方法,包括其基本概念、默认构造方法、构造方法的重载、构造方法的细节以及执行顺序。通过具体示例,详细解释了构造方法在对象初始化中的重要作用,帮助读者在面试中更好地应对相关问题。
25 1
|
2月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
33 3
|
2月前
经典面试题:用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
在 C 语言中,使用 `#define` 预处理指令可以为常量命名,提高代码可读性和易维护性。通过基本时间单位换算(1 年 = 365 天 × 24 小时 × 60 分钟 × 60 秒),可以计算出一年中的总秒数,并将其定义为 `SECONDS_IN_A_YEAR`。示例代码展示了如何定义和打印这一常量,最终输出一年中有 31536000 秒。
78 15
|
4月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
|
4月前
|
Go 数据库 UED
[go 面试] 同步与异步:程序执行方式的不同之处
[go 面试] 同步与异步:程序执行方式的不同之处
|
5月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
82 1
|
6月前
|
SQL 存储 前端开发
程序技术好文:面试知识点六:JavaWeb
程序技术好文:面试知识点六:JavaWeb
50 1
|
7月前
|
Python
2024年最新【Python】程序的组织结构:顺序结构,2024年最新46道面试题带你了解中高级Python面试
2024年最新【Python】程序的组织结构:顺序结构,2024年最新46道面试题带你了解中高级Python面试
2024年最新【Python】程序的组织结构:顺序结构,2024年最新46道面试题带你了解中高级Python面试
|
5月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
71 0
|
5月前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
52 0