第六十一天学习记录:C语言进阶:C语言预处理1

news2024/11/29 6:35:35

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

在ANSI C的任何一种实现中,存在两个不同的环境。
第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。第2种是执行环境,它用于实际执行代码。

详解编译+链接

翻译环境

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/04bd03e2cb554aa298fb6a8349722f89.png
在这里插入图片描述

上图截取自比特科技免费课程

。组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
。每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
。链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

Linux环境方便观察编译过程:
1、预处理 选项gcc -E test.c -o test.i 预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。
2、编译 选项gcc -S test.c编译完成之后就停下来,结果保存在test.s中。
3、汇编 gcc -c test.c汇编完成之后就停下来,结果保存在test.o中。

比特科技推荐网站:
VIM学习资料
简明VIM练级攻略:
https://coolshell.cn/articles/5426.html
给程序员的VIM速查卡
https://coolshell.cn/articles/5479.html

运行环境

程序执行的过程:
1、程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2、程序的执行便开始。接着便调用main函数。
3、开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4、终止程序。正常终止main函数;也有可能是意外终止。

问:在编译过程中实现的内存堆栈和通过exe运行程序时进行的内存堆栈是不是一样的?
ChatAI答:
在编译过程中实现的内存堆栈和通过exe运行程序时进行的内存堆栈是不一样的。

在编译过程中,内存堆栈是由编译器实现的,用于在程序执行时为函数、变量等分配内存空间和管理内存使用情况。编译器会根据程序的代码框架和变量的作用域等因素,对内存空间进行分配和释放,并且对程序和函数的调用栈进行跟踪和管理。

在执行程序时,内存堆栈也存在,但实现方式是由操作系统和运行时环境决定的。当程序运行时,操作系统会为程序分配一定的内存空间,这些内存空间被划分为不同的存储区域,包括进程虚拟地址空间、栈、堆、全局/静态数据区等。程序使用内存空间时,根据内存空间的访问类型和权限进行对应的操作。

因此,编译器实现的内存堆栈和运行时环境实现的内存堆栈,并不是完全相同的。它们的实现方式、管理机制、内存分配和释放方式等都可能存在差异。这也是为什么在一些情况下,程序在编译时可以通过编译,但在执行时却会出现运行时错误的原因之一。

《程序员的自我修养》

预处理详解

预定义符号

__FILE__				//进行编译的源文件
__LINE__				//文件当前的行号
__DATE__				//文件被编译的日期
__TIME__				//文件被编译的时间
__STDC__				//如果编译器遵循ANSI C,其值为1,否则未定义(PS:VS2015无效)
__FUNCTION__     //打印函数名

这些预定义符号都是语言内置的。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	printf("file:%s line:%d\n",__FILE__,__LINE__);
	printf("date:%s time:%s\n",__DATE__,__TIME__);
	return 0;
}

在这里插入图片描述
用于写日志文件:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	//写日志文件
	int i = 0;
	int arr[10] = { 0 };
	FILE* pf = fopen("log.txt", "w");
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
		fprintf(pf, "file:%s line:%d date:%s time:%s i=%d\n",
			__FILE__, __LINE__, __DATE__, __TIME__,i);
	}
	fclose(pf);
	pf = NULL;
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

预处理指令:

#define
#include
#pragma
#if
#endif
#ifdef
#line

#define

#define定义标识符

语法:
#define name stuff
举个例子:

#define MAX 1000
#define reg register            //为 register 这个关键字,创建一个简短的名字
#define do_forever for(;;)   //用更形象的符号来替换一种实现
#define CASE break;case //在写case语句的时候自动把break写上
//如果定义的stuff过长,可以分成几行写,除了最后一行外,每行的后面都加上一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t    \
											date:%s\ttime:%s\n,    \
											__FILE__,__LINE__,   \
											__DATE__,__TIME__)

#define定义宏

#defne 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
下面是宏的声明方式:

#define name( parament-list ) stuff其中的parament-list是一个由逗号隔开的符号表,它们可能出现在stuff中。

注意:参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
如:

#define SQUARE( x ) x*x

这个宏接收一个参数x,如果在上述声明之后,你把

SQUARE( 5 );

置于程序中,预处理器就会用下面这个表达式替换上面的表达式:

5*5
#include <stdio.h>
#define SQUARE(X) X*X

int main()
{
	int ret = SQUARE(5);
	printf("%d\n",ret);
	return 0;
}

输出:25

#include <stdio.h>
#define SQUARE(X) X*X

int main()
{
	int ret = SQUARE(5+1);
	printf("%d\n",ret);
	return 0;
}

输出:11
注意:宏是用来替换的而不是传参的。上面被替换成了:

5+1*5+1   =   11

建议优化写法:

#define SQUARE(X) ((X)*(X))

define替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1、在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2、替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3、最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1、宏参数和#define定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
2、当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

#和##

如何把参数插入到字符串中?

#include <stdio.h>
#define PRINT(X) printf("the value of "#X" is %d\n",X)

int main()
{
	int a = 10;
	int b = 20;
	PRINT(a);
	PRINT(b);
	return 0;
}

在这里插入图片描述
另一个技巧是:使用#,把一个宏参数变成对应的字符串。比如:

#include <stdio.h>
#define PRINT(FORMAT,VALUE)\
	printf("the value of "#VALUE" is "FORMAT"\n",VALUE)

int main()
{
	int a = 10;
	int b = 20;
	PRINT("%d",a+8);
	PRINT("%d",b+3);
	return 0;
}

在这里插入图片描述

##的作用

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


#include <stdio.h>

#define CAT(X,Y) X##Y

int main()
{
	int chung1991 = 2023;
	printf("%d\n", CAT(chung, 1991));
	return 0;
}

输出:2023
注:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。

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

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

相关文章

实战:单点登录的两种实现方式,附源码

最近工作有点忙&#xff0c;好久没更新文章了&#xff0c;正好这两天在整理单点登陆相关的文档&#xff0c;今天趁着小孩睡着了&#x1f92b;&#xff0c;赶紧码一篇实战文交差。 概念 单点登录&#xff08;Single Sign-On&#xff0c;SSO&#xff09;是一种身份验证服务&…

机器学习常识 13: PCA

摘要: 主成分分析 (principal component analysis, PCA) 是一种有理论依据的无监督特征提取的线性方法. 1. 特征选择与特征提取 特征选择是指从已有的特征里面选择出一个子集. 例如: 身高、体重、性别、年龄、体温、血相等等, 如果要一个人是否患流感&#xff0c;身高、体重等…

OpenMMLab-AI实战营第二期——1. 计算机视觉与OpenMMLab概述

文章目录 1. 课程内容概述1.1 Openmmlab框架1.2 课程其他说明 2. mmcv安装2.1 正确步骤2.2 debug2.3 错误探索 1. 课程内容概述 个人更关注语义分割和3D方面的内容&#xff0c;所以这里重点记录这两点相关的。 1.1 Openmmlab框架 具体的模块&#xff0c;详见&#xff1a;http…

wy的leetcode刷题记录_Day67

wy的leetcode刷题记录_Day67 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2023-6-1 前言 目录 wy的leetcode刷题记录_Day67声明前言1019. 链表中的下一个更大节点题目介绍思路代码收获 1019. 链表中的下一个更大节点 222. 完全二叉树…

UUOffice 工具箱,一款功能强大的 Excel 办公插件,好用推荐 ~

简介 UUOffice 工具箱,是一款功能强大的Office插件&#xff0c;功能强大&#xff0c;有着各种的单元格及文本的处理工具&#xff0c;自定义扩展函数&#xff0c;批注管理&#xff0c;图片导入导出&#xff0c;工作表汇总&#xff0c;联想输入等等超多实用工具&#xff0c;对日…

奇葩算法——猴子排序

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;猴子排序 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪发光的社区…

Docker下载遇到的报错以及解决记录

目录 一、docker介绍 1. Docker引擎 2. Docker镜像 3. Docker容器 4. Docker仓库 5. Docker网络 二、docker下载 1.首先再官方下载好docker 2.在我打开时出现了下面的错误&#xff1a; 然后我下载了一个wsl 然后就可以正常打开了 &#xff08;2&#xff09;如果自己的电…

「学习IT技术和编写高质量代码的经验和建议」

一、你在编写代码时&#xff0c;会特别注意哪些流程&#xff1f; 在编写代码的过程中&#xff0c;我通常会特别注意以下流程&#xff1a; 输入验证&#xff1a;确保输入的参数满足预期&#xff0c;防止出现非法输入导致的安全问题或异常错误。 异常处理&#xff1a;在代码中添…

迅为全国产ATX3A5000_7A2000主板-龙芯平台安装 开源loongnix系统

Loongnix下载 Loongnix桌面版镜像:有基于mate主题的版本和基于cartoon主题的版本。本章节的安装 步骤以cartoon主题的安装方式为例&#xff0c;mate主题的ISO安装步骤与cartoon主题的安装方式类 似。 1.1 引导和开始安装 主机启动后,BIOS从U盘引导启动系统&#xff0c;出现…

Vue组件化、通过自定义指令子组件向父组件传递、$nextTick

1.如何安装Vue脚手架&#xff1f; 第一步&#xff08;仅第一次执行&#xff09;&#xff1a;全局安装vue/clinpm install -g vue/cli 第二步&#xff1a;切换到你要创建项目的目录&#xff0c;然后使用命令创建项目vue create xxxx 第三步&#xff1a;启动项目npm run serve 2…

chatgpt赋能python:Python中的或且非

Python中的或且非 Python语言中的逻辑运算符包括&#xff1a;或、与、非&#xff0c;分别用 “|”、“&”、"~"符号表示。 或运算符&#xff08;|&#xff09; 当两个操作数中有一个为True时&#xff0c;结果为True。 例如&#xff1a; a 1 b 2 c 3 if a…

Qt概述和项目文件介绍

注意&#xff1a;学习本专栏的内容需要了解C相关知识&#xff0c;会涉及到C基础语法和相关特性&#xff0c;可以参考我的另一个专栏 c从零开始_小梁今天敲代码了吗的博客-CSDN博客 目录 一.什么是Qt 二.Qt的案例 三.项目文件介绍 一.什么是Qt 是一个跨平台的 C 应用程序…

YOLOV5 + PYQT5双目测距(二)

YOLOV5 PYQT5双目测距 1. 测距源码2. 测距原理3. PYQT环境配置4. 实验4.1 下载源码14.2 复制源码2文件夹4.3 创建py文件4.4 实验结果 1. 测距源码 详见文章 YOLOV5 双目测距&#xff08;python&#xff09; 2. 测距原理 如果想了解双目测距原理&#xff0c;请移步该文章 双…

chatgpt赋能python:Python中的行与列:从入门到精通

Python中的行与列&#xff1a;从入门到精通 Python是一种高级编程语言&#xff0c;广泛用于计算机编程领域。在Python中&#xff0c;行和列是编程过程中不可或缺的元素&#xff0c;因为它们代表着代码中最基本的构建块。本文将介绍Python中的行和列&#xff0c;并探讨它们在程…

【python】之loguru库,好用的日志管理库!

在 Python 中用到日志记录&#xff0c;那就不可避免地会用到内置的 logging标准库 。虽然logging 库采用的是模块化设计&#xff0c;你可以设置不同的 handler 来进行组合&#xff0c;但是在配置上通常较为繁琐&#xff1b;而且如果不是特别处理&#xff0c;在一些多线程或多进…

linux进程间通信(信号量)

信号量是一个特殊的变量&#xff0c;程序对其访问都是原子操作&#xff0c;且只允许对它进行等待&#xff08;即 P(信号变量))和发 送&#xff08;即 V(信号变量))信息操作。最简单的信号量是只能取 0 和 1 的变量&#xff0c;这也是信号量最常见的一种形式&#xff0c; 叫做二…

由于找不到iutils.dll而造成的错误,要怎么去解决?

在使用电脑或运行某些软件时&#xff0c;有时会遇到“找不到iutils.dll”的错误提示。这个错误通常表示缺少iutils.dll文件或者该文件已经损坏。如果你遇到了这个问题&#xff0c;不要担心&#xff0c;因为有很多方法可以解决这个问题。下面我们一起来看看找不到iutils.dll的问…

在spring容器启动后监听事件ApplicationReadyEvent

概述 经常会在业务中遇到需要在项目启动后刷新/预热一些数据的要求。 常见可以监听ApplicationReadyEvent和ContextRefreshedEvent. 但是因为常见的springboot项目都依赖的springmvc&#xff0c;所以实际上有2个容器&#xff0c;spring的ioc容器是springmvc的父容器。 而且C…

电脑上怎么录屏?2个好用的电脑录屏方法分享!

案例&#xff1a;怎么在电脑上录屏&#xff1f; 【我想分享我电脑上的操作、游戏画面给我的朋友&#xff0c;但是我不知道如何录制电脑屏幕。有没有详细的电脑录屏方法&#xff0c;在线蹲一个&#xff01;】 你是否曾经遇到这样的情况&#xff1a;需要录制电脑屏幕上的一些操…

ICLR2023 | RetMol:基于检索的可控分子生成

题目&#xff1a;Retrieval-based Controllable Molecule Generation 文章地址&#xff1a;https://openreview.net/pdf?idvDFA1tpuLvk 代码地址&#xff1a;GitHub - NVlabs/RetMol: A new retrieval-based framework for controllable molecule generation. 主题&#xf…