C语言程序设计——程序环境和预处理

news2024/9/29 9:31:57

一、翻译环境

(1)组成一个程序的每个源文件,通过翻译过程分布转换成对应的目标代码;

(2)每个目标文件由链接器链接到一起,形成一个单一而完整的可执行程序;

(3)链接器同时还会引入标准库中任何被该程序所使用到的函数,而且它还可以搜索程序员个人的程序库,将其所需要的函数也一同链接到程序中。

二、程序编译与运行

1. 程序编译的四个阶段

1.1 预处理

(1)引入头文件;

(2)去掉注释;

(3)宏替换;

……

1.2 编译

(1)语法分析;

(2)词法分析;

(3)符号汇总;

(4)语义分析;

……

        把高级语言代码翻译成与之等价的汇编指令。

1.3 汇编

        把汇编代码转换为与之等价的二进制机器指令。

1.4 链接

        将机器指令与之所使用的库函数对应库文件中的机器指令打包到一起,组织成为可执行程序。

 2. 运行环境

程序的执行过程:

        (1)程序运行必须载入到内存中。在操作系统环境中:这个操作一般由操作系统完成;在独立环境中:程序的载入必须由手工完成,也可能通过可执行代码置入只读内存来完成。

        (2)程序执行开始,紧接着调用main函数。

        (3)开始执行程序代码:此时程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储于静态内存中的变量在程序的整个执行过程中一直保持有效。

        (4)程序终止:正常终止于main函数返回,也可能在程序运行过程中发生意外终止。

三、详解预处理

1. 预定义符号

__FILE__  // 进行编译的源文件
__LINE__  // 文件当前的行号
__DATE__  // 文件编译的日期
__TIME__  // 文件被编译的时间
__STDC__  // 若编译遵循ANSI C,值为1;否则未定义

示例:

2. #define

2.1 定义标识符

(1)语法

#define name stuff

(2)示例

#define MAX 100
#define name "zhangsan"
#define null NULL
#define llt long long int

2.2 定义宏

(1)定义

        #define机制包括了一个规定:允许把参数替换到文本中,这种实现通常称为宏或定义宏。

宏的声明方式:

#define name(parament-list) stuff

parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中

(2)示例

(3)注意

        参数列表左括号必须与name紧邻,否则参数列表会被解释为stuff的一部分。 

2.3 宏替换规则

        在程序中扩展#define定义符号和宏时,需要涉及以下几个步骤:

        (1)在调用宏时,首先对参数进行检查,查看是否包含任何由#define定义的符号,若有则它们首先被替换。

        (2)替换文本随后被插入到程序中原来文本的位置;对于宏,参数名被它们的值所替换。

        (3)最后再次对结果文件进行扫描,查看是否包含任何由#define定义的符号,若有则重复上述处理过程。

注意:

        (1)宏参数和#define定义中可用出现其他#define定义的变量,但是宏不能出现递归。

        (2)当预处理器搜索#define定义的符号的时候,字符串常量的内容并不会被搜索(也就是字符串常量中的,不会被当作宏进行处理)。

2.4 # 和 ##

(1)#的作用

        将宏参数转换为对应的字符串。

示例:

(2)##的作用

        把位于它两边的符号合成为一个符号;它允许宏定义从分离的文本片段创建标识符。

注意:

        这样的连接必须产生的是合法的标识符,否则其结果就是未定义。

示例:

2.5 宏与函数对比

         宏通常被应用于执行简单的运算。

宏的优势:

(1)宏比函数在程序的规模和速度方面更优

        用于调用函数和从函数返回的代码可能比实际执行这个小型计算所需的时间更多。

(2)宏是类型无关的

        函数的参数必须声明为特定的类型,所以函数只能在类型合适的表达式上使用;宏可以适用于多种类型。

(3)宏的参数可以出现类型

宏的劣势:

(1)一份宏定义的代码将嵌入到程序中,若宏较长则可能大幅增加程序的长度。

(2)宏不方便调试。

(3)因为宏是类型无关的,所以存在不够严谨问题。

(4)宏可能带来运算符优先级问题,导致程序容易出错。

(5)宏不能递归。

3. #undef

(1)功能

        移除一个宏定义。

(2)示例

4. 条件编译

4.1 单分支条件编译

#if 常量表达式
	// ……
#endif

        常量表达式由预处理器求值,为真则编译之间的内容,否则不参与编译。

4.2 多分支条件编译

#if 常量表达式
	// ……
#elif 常量表达式
	// ……
#else
	// ……
#endif

4.3 判断是否被定义

// 判断symbol是否定义,定义则编译
#if defined(symbol)
// #ifdef symbol  等价
#endif

// 判断symbol是否定义,未定义则编译
#if !defined(symbol)
// #ifndef symbol  等价
#endif

4.4 嵌套指令

#if defined(OS_UNIX)
	#ifdef OPTION1
		// ...
	#endif
	#ifdef OPTION2
		// ...
	#endif
#elif defined(OS_MSDOS)
	#ifdef OPTION2
		// ...
	#endif
#endif

5. 文件包含

5.1 库文件包含

#include <filename>

查找策略:

        直接在标准路径下(编译器提供的标准库目录中)去查找,若找不到则编译报错。

5.2 本地文件包含

#include "filename"

查找策略:

        先在源文件所在目录下查找;若未找到,则编译器像查找库函数头文件一样在标准位置查找;若还是未找到,则编译报错。

5.3 嵌套文件包含

(1)问题引入

        若头文件内包含了其他头文件,则可能引发嵌套包含,在预处理引入头文件时就会产生重复引入问题,导致程序臃肿。

(2)解决方法

①条件编译

#ifdef __TEST_H__
#define __TEST_H__
// 头文件内容
#endif

②#pragma once

        在文件开头添加#pragma once指令。

四、模拟实现offsetof

1. offsetof功能介绍

offsetof(type, member)

       offsetof是一个宏,功能是计算一个结构体变量相较于结构体起始位置的偏移量。

type:结构体类型

member:结构体成员

2. 模拟实现

#define OFFSETOF(type, name) ((size_t)&(((type*)0)->name))

        将0地址强转为结构体类型的指针,则认为在0地址处存放的是一个该结构体,然后获取指定成员的地址,将地址值强转为整型,即它相对于0地址的偏移量,即该成员相对于结构体起始地址的偏移量。

测试:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/803623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于ESP8266+网络调试助手点灯实验

文章目录 ESP8266串口wifi模块简介实验准备硬件接线程序下载注意事项总结 ESP8266串口wifi模块 简介 ESP8266 是一种低成本、高性能的 Wi-Fi 模块&#xff0c;内置了 TCP/IP 协议栈&#xff0c;它可以作为单独的无线网络控制器&#xff0c;或者与其他微控制器进行串口通信。它…

Linux之 Vim 搜索方式

方式一&#xff1a;快速搜索&#xff08;字符串完全匹配&#xff0c;区分大小写&#xff09; 格式&#xff1a; / 关键词 or &#xff1f; 关键词 /内容 #按回车键搜索 从上到下查找 ?内容 #按回车键搜索 从下到上查找 优点&#xff1a;快速定位到该关键字 回车之后&…

Spark(37):Streaming DataFrame 和 Streaming DataSet 创建

目录 0. 相关文章链接 1. 概述 2. socket source 3. file source 3.1. 读取普通文件夹内的文件 3.2. 读取自动分区的文件夹内的文件 4. kafka source 4.1. 导入依赖 4.2. 以 Streaming 模式创建 Kafka 工作流 4.3. 通过 Batch 模式创建 Kafka 工作流 5. Rate Source…

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测

回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测 目录 回归预测 | MATLAB实现PSO-GPR粒子群优化高斯过程回归多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab基于PSO-GPR基于粒子群算法优化高斯过程回归的数据回归预…

Jmeter经过处理的变量设置全局变量

之前遇到一个问题&#xff1a;项目的某些接口是需要登录的而且登录不能多用户登录。模拟登录的时候传入请求头的其中一个参数比较复杂&#xff0c;需要登录后的某些参数拼接和加密后设置成全局变量&#xff0c;在请求头中调用这个变量&#xff0c;正常的设置全局变量的方法百度…

Java NIO 详解

Java 从1.4开始引入NIO&#xff08;New IO&#xff09;&#xff0c;是一种基于块&#xff08;Block&#xff09;的IO机制&#xff0c;也称为非阻塞IO。相比于传统的Java IO&#xff08;IO流&#xff09;方式&#xff0c;Java NIO提供了更快速、高效、灵活的IO操作。 Java NIO的…

一文让你彻底搞懂Mybatis之缓存机制

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 文章目录 一. 缓存是什么&#xff1f;二. 为什么要使用缓存&#xff1f;三. Mybatis中的缓存分哪几种&#…

自己实现MyBatis 底层机制--抽丝剥茧(上)

&#x1f600;前言 本篇博文是学习过程中的笔记和对于MyBatis底层机制的分析思路&#xff0c;希望能够给您带来帮助&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到…

Base64之间的相互转化

使用org.apache.ommons.codec.binary.Base64实现字符串和Base64之间的相互转化 字符串转化为Base64之间的相互转化一 //转化为Base64字符串 String strOld "Welcome to the new world"; base64EncodeStr Base64.encodeBase64String(strOld.getBytes()); System.o…

黑马点评项目学习笔记(15w字详解,堪称史上最详细,欢迎收藏)

黑马点评项目学习笔记 文章目录 黑马点评项目学习笔记前言项目搭建导入数据库初始化项目启动项目启动前端项目启动后端项目 基于Session实现短信验证码登录短信验证码登录配置登录拦截器数据脱敏 Session集群共享问题基于Redis实现短信验证码登录短信验证登录配置登录拦截器 店…

漏洞分析|Metabase 代码执行漏洞(CVE-2023-38646):H2 JDBC 深入利用

0x01 概述 最近 Metabase 出了一个远程代码执行漏洞&#xff08;CVE-2023-38646&#xff09;&#xff0c;我们通过研究分析发现该漏洞是通过 JDBC 来利用的。在 Metabase 中兼容了多种数据库&#xff0c;本次漏洞中主要通过 H2 JDBC 连接信息触发漏洞。目前公开针对 H2 数据库…

国产内存强势崛起,光威神条有神价,无套路闭眼可入

今年的DIY电脑市场终于摆脱了前两年的阴霾&#xff0c;从CPU到内存都有着充足的货源&#xff0c;而且价格靠谱&#xff0c;特别是国产存储品牌超级厚道&#xff0c;内存、硬盘等配件的价格基本都是大跳水&#xff0c;相比于去年&#xff0c;同样的价格能够买到容量和性能翻倍的…

ERROR 1064 - You have an error in your SQL syntax;

ERROR 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near (/, 少个逗号吧&#xff0c;以前开始写SQL&#xff0c;特别是修改SQL的时候容易出现这样错误。 而且自己也知道在附近…

SAP财务系统中的“复式记账法”

1. 前言 “复式记账法”是财务的基础知识&#xff0c;对于财务出身的小伙伴是so easy&#xff0c;但对于技术出身的同学&#xff0c;通常会被“借贷”关系弄的晕头转向。 本文会简明扼要的总结“复式记账法”的基本原理&#xff0c;并以采购和销售流程为例来介绍如何进行复式…

Java - 注解开发

注解开发定义bean Component的衍生注解 Service&#xff1a; 服务层的注解 Repository&#xff1a; 数据层的注解 Controller&#xff1a; 控制层的注解 纯注解开发 bean管理 bean作用范围 在类上面添加Scope(“singleton”) // prototype: 非单例 bean生命周期 PostCon…

PyTorch BatchNorm2d详解

通常和卷积层&#xff0c;激活函数一起使用

基于51单片机和proteus的加热洗手器系统设计

此系统是基于51单片机和proteus的仿真设计&#xff0c;功能如下&#xff1a; 1. 检测到人手后开启出水及加热。 2. LED指示加热出水及系统运行状态。 功能框图如下&#xff1a; Proteus仿真界面如下&#xff1a; 下面就各个模块逐一介绍&#xff0c; 模拟人手检测模块 通过…

redis 第三章

目录 1.主从复制 2.哨兵 3.集群 4.总结 1.主从复制 结果&#xff1a; 2.哨兵 3.集群 4.总结 通过集群&#xff0c;redis 解决了写操作无法负载均衡&#xff0c;以及存储能力受到单机限制的问题&#xff0c;实现了较为完善的高可用方案。

【设计模式】详解单例设计模式(包含并发、JVM)

文章目录 1、背景2、单例模式3、代码实现1、第一种实现&#xff08;饿汉式&#xff09;为什么属性都是static的&#xff1f;2、第二种实现&#xff08;懒汉式&#xff0c;线程不安全&#xff09;3、第三种实现&#xff08;懒汉式&#xff0c;线程安全&#xff09;4、第四种实现…

Android kotlin系列讲解之最佳的UI体验 - Material Design 实战

目录 一、什么是Material Design二、Toolbar三、滑动菜单1、DrawerLayout2、NavigationView 四、悬浮按钮和可交互提示1、FloatingActionButton2、Snackbar3、CoordinatorLayout 五、卡片式布局1、MaterialCardView2、AppBarLayout 六、可折叠式标题栏1、CollapsingToolbarLayo…