由浅到深认识C语言(7):预处理二进制

该文章Github地址:https://github.com/AntonyCheng/c-notes

在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!

上一章:由浅到深认识C语言(6):变量的存储类型

6.预处理

6.1.C语言编译过程

  1. 预处理:头文件包含、宏替换、条件编译、删除注释,不做语法检查;

    #include<stdio.h>
    
  2. 编译:将预处理后的文件生成汇编文件,并且进行语法检查;

  3. 汇编:将汇编文件编译成二进制文件;

  4. 链接:将“众多的二进制文件+库函数+启动代码”生成可执行文件(.exe等);

6.2.头文件包含

  • <>用于包含系统的头文件
#include<hello.h>

上面代码表示在系统指定的目录下寻找 hello.h

  • ""用于包含用户自定义的头文件
#include"hello.h"

上面代码表示先从源文件所在的目录寻找 hello.h ,如果找不到再到系统指定的目录下寻找;

  • include只能包含头文件.h,不要去包含源文件.c

6.3.define 宏

定义:在源代码中允许一个标识符(宏名)来表示一个语言符号的字符串,用特定的符号来代表指定的信息;

优点:提高代码的可读性和移植性;

#include<stdio.h>
#define N 10
static void test() {
	int i = 0;
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	for (i = 0; i < N; i++) {
		printf("%d ", i);
	}
	return;
}
int main(int argc, char *argv[]) {
    test();
	return 0;
}

打印效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

过程:上例的过程是将代码中的 10 转变成了 N ,如果需要修改 10 这一个数值的话,仅需改变宏,该过程被称之为“宏展开”;

注意:宏的后方不能加分号,因为加了分号,编译器就会把分号给编进宏内,宏一般为大写,以便和普通变量区分开来;

分类

  1. 无参数的宏:

    #define 宏名 代替内容

    例如:#define PI 3.14f

    例如:

    #include<stdio.h>
    #define N 10
    static void test() {
    	int i = 0;
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    #undef N
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	for (i = 0; i < N; i++) {
    		printf("%d ", i);
    	}
    	return;
    }
    int main(int argc, char *argv[]) {
    	test();
    	return 0;
    }
    

    注意

    • 宏只在当前源文件有效,当需要终止宏的作用范围时需要 #undef 宏名 ,例如上;
    • 这种方法能使用户能以一个简单的名字代替一个长的内容(数字,字符,字符串)
  2. 带参数的宏(宏函数):

    #define 宏名(形参表) 被替代内容;

    例如:#define N(a,b) a+b;

    注意:参数表中的参数不能写类型,即 N(int a,int b) 是错的;

    例如:

    #define MY_ADD(a,b) a+b
    //调用宏
    MY_ADD(10,20); //这里等价于 10 + 20;
    

    注意:千万不要擅自加括号,比如求 MY_ADD(10+10,20+20); 那么求得的过程就是 10+10*20+20

    案例一:两数相加;

    #include<stdio.h>
    #define MY_ADD(a,b) a+b
    static void test() {
    	int num = 0;
    	num = MY_ADD(10 , 20);
    	printf("num = %d\n", num);
    	return;
    }
    int main(int argc, char *argv[]) {
    	test();
    	return 0;
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    案例二:两数相乘;

    #include<stdio.h>
    #define MY_MUL(a,b) a*b
    static void test() {
    	int num = 0;
    	num = MY_ADD(10 , 20);
    	printf("num = %d\n", num);
    	return;
    }
    int main(int argc, char *argv[]) {
    	test();
    	return 0;
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  3. 宏函数和普通函数的区别

    宏函数调用多少次,就会宏展开多少次,执行代码的时候没有函数调用的过程,也不需要函数的出入栈,所以带参数的宏会浪费空间,节省了时间;

    普通函数代码只有一份,存在代码段,调用的时候去代码段读取函数指令,调用的时候要压栈(保存调用函数前的相关信息),调用完之后会出栈(恢复调用前的相关信息),所以函数浪费了时间,节省了空间;

  4. 案例:求出下例printf

    #include<stdio.h>
    #define MY_MUL(a,b) a*b
    #define MY_ADD(a,b) a+b
    static void test() {
    	printf("%d\n", MY_MUL(MY_ADD(10 + 10, 20 + 20), MY_MUL(10 + 10, 20 + 20)));
        //列算式出来就是 10 + 10 + 20 + 20 * 10 + 10 * 20 +20 = 460
    	return;
    }
    int main(int argc, char *argv[]) {
    	test();
    	return 0;
    }
    

    打印效果如下:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6.4.条件编译

一般情况下,源程序中所有行都参加编译,但有时希望对部分源程序行只在满足一定条件时才编译,即对这部分源程序行指定编译条件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注意:以下案例在 Linux下测试;

案例一:测试不存在;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试预处理结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

案例二:测试存在;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试预处理结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

案例三:判断表达式;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

变蓝表示不编译

综合案例:通过条件编译来控制大小写的转换;

#include<stdio.h>
int main(int argc, char *argv[]) {
	char str[128] = { "" };
	int i = 0;
	printf("请输入一个字符串:");
	//fgets 会获取换行符“\n”
	fgets(str, sizeof(str), stdin);
	//去掉换行符,strlen返回的是字符串的实际长度,不包括“\0”
	str[strlen(str) - 1] = 0;  //strlen[str] 是换行符的下标位置
#if 1
	//大写变小写
	while (str[i] != '\0') {
		if (str[i] >= 'A' && str[i] <= 'Z') {
			str[i] = str[i] + 32;
		}
		i++;
	}
#else
	//小写变大写
	while (str[i] != '\0') {
		if (str[i] >= 'a' && str[i] <= 'z') {
			str[i] -= 32;
		}
		i++;
	}
#endif
	printf("str = %s\n", str);
	return 0;
}
由于条件变量为 1 ,即编译大写变小写;

6.5.防止头文件重复包含

  • 方法一:编译器层面 #pragma once

    在所有头文件上方写上 #pragma once ,例如下:

    #pragma once
    #include"a.h"
    #include"b.h"
    #include"c.h"
    
  • 方法二:C++层面 #ifndef 宏……#define 宏……头文件具体内容……#endif

    例如下:

    main.c

    #include<stdio.h>
    #include"a.h"
    #include "b.h"
    int main(int argc,char *argv[]){
    	printf("num = %d\n",num);
    	return 0;
    }
    

    a.h

    #ifndef __A_H__
    #define __A_H__
    #include "b.h"
    #endif
    

    b.h

    #ifndef __B_H__
    #define __B_H__
    int num = 10;
    #endif
    
  • 总结:

    #pragma once 编译器决定,强调的文件名;

    #ifndef 是C/C++标准制定,强调的是宏而不是文件;

7.二进制 原/反/补码

无符号数和正数负数
概念10概念-10
原码数据的二进制形式0000 1010原码数据的二进制形式1000 1010
反码和原码相同0000 1010反码原码的符号位不变,其他取反1111 0101
补码和原码相同0000 1010补码反码 + 11111 0110

注意

  1. 无符号数和正数——原码==反码==补码
  2. 负数——
    • 反码==原码的符号位不变,其他位取反
    • 补码=反码 + 1
  3. 任何数据在计算机中都是以补码形式存储

计算机为什么要补码?

补码将减法运算转换成加法运算:

计算下式:
6 - 10 == -4
6 + (-10) == -4
如果没有补码:
  0000 0110
+ 1000 1010
-------------
  1001 0000 == -16(错误)
如果有补码:
  0000 0110
+ 1111 0110
-------------
  1111 1100 --> 1000 0011 --> 1000 0100 == -4

补码统一了零的编码:

有符号数:1111 1111 ~ 1000 0000 ~ 0000 0000 ~ 0111 1111
		  -127    ~    -0     ~    +0     ~    +127
		计算机为了扩大数据的表示范围,故意将 -0 看成了 -128
		所以范围是 -128 ~ 127
无符号数:0000 0000 ~ 1111 1111
		范围是 0 ~ 255
即:
+0 == 0000 0000(原) == 0000 0000(反) == 0000 0000(补)
-0 == 1000 0000(原) == 1111 1111(反) == 0000 0000(补)

补码意义:将减法运算变加法运算,同时统一了零的编码。

下一章:由浅到深认识C语言(8):指针的概念与应用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Oracle19C静默安装教程

一、安装前的准备 1、安装Linux操作系统 红帽Linux安装教程 2、配置网络源或者本地源 网络源&#xff1a;网络源配置方法 本地源&#xff1a;本地源配置方法 3、hosts文件配置 配置hostname&#xff1a; hostnamectl set-hostname p19c配置hosts文件&#xff1a; cat &…

从零开始写 Docker(七)---实现 mydocker commit 打包容器成镜像

本文为从零开始写 Docker 系列第七篇&#xff0c;实现类似 docker commit 的功能&#xff0c;把运行状态的容器存储成镜像保存下来。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识&#xff1a; 核心原…

多个线程交替打印ABC

多个线程交替打印ABC package 多个线程交替打印ABC;import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;/*** Created with IntelliJ IDEA.** Author: AlenXu* Date: 2024/03/20/10:10* Description:*/ public class ThreadLoopP…

数字功放VS模拟功放,选择适合你的音频解决方案

数字功放和模拟功放是音频系统中常用的两种功放技术&#xff0c;适用于不同的音频应用&#xff0c;都具有各自的优势和特点。本文将为您详细介绍数字功放和模拟功放的差异&#xff0c;并帮助您找到适合自己的音频解决方案。 1、数字功放是一种利用数字信号处理技术的功放。它将…

0基础 三个月掌握C语言(13)

数据在内存中的存储 整数在内存中的存储 在讲解操作符时 我们就已经学习了该部分的内容 这里我们回顾一下 整数的二进制表示方法有三种&#xff1a;原码 反码 补码 有符号的整数&#xff08;unsigned&#xff09; 三种表达方式均有符号位和数值位两部分 最高位的一位被当…

【C语言步行梯】C语言实现扫雷游戏(含详细分析)

&#x1f3af;每日努力一点点&#xff0c;技术进步看得见 &#x1f3e0;专栏介绍&#xff1a;【C语言步行梯】专栏用于介绍C语言相关内容&#xff0c;每篇文章将通过图片代码片段网络相关题目的方式编写&#xff0c;欢迎订阅~~ 文章目录 需求分析具体实现主函数体菜单实现游戏实…

AI预测福彩3D第14弹【2024年3月20日预测--新算法重新开始计算第11次测试】

今天继续对第一套算法进行测试。废话不多说了&#xff0c;直接上分析出的图表&#xff0c;再上结果。 最终&#xff0c;经过研判分析&#xff0c;2024年3月20日福彩3D的七码预测结果如下&#xff1a; 百位&#xff1a;7 8 4 3 5 6 9(1换9) 十位&#xff1a;5 4 3 6 1 2 0(07分一…

day14-SpringBoot 原理篇

一、配置优先级 SpringBoot 中支持三种格式的配置文件&#xff1a; 注意事项 虽然 springboot 支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐统一使用一种格式的配置 &#xff08;yml 是主流&#xff09;。 配置文件优先级排名&#xff08;从高到低&…

事务同步管理器TransactionSynchronizationManager

事务同步管理器的使用场景&#xff1a; 同步涉及的资源包括&#xff1a;SqlSession & Connection。同步资源核心目的是线程共享&#xff0c;意味着必须跟线程绑定。同步资源伴随着线程生存或者消亡&#xff0c;意味着线程结束之前必须手动清除其绑定的资源。事务同步管理器…

基于SpringBoot+Redis实现接口限流

前言 业务中需要对一些接口进行限流处理&#xff0c;防止机器人调用或者保证服务质量&#xff1b; 实现方式 基于redis的lua脚本 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…

Linux Deepin系统安装x11vnc+cpolar实现Windows系统电脑远程其桌面

文章目录 1. 安装x11vnc2. 本地远程连接测试3. Deepin安装Cpolar4. 配置公网远程地址5. 公网远程连接Deepin桌面6. 固定连接公网地址7. 固定公网地址连接测试 x11vnc是一种在Linux系统中实现远程桌面控制的工具&#xff0c;它的原理是通过X Window系统的协议来实现远程桌面的展…

linux用git拉取我云端以及git处理冲突

拉取后切换一个跟云端分支(dev)一样的 git branch --set-upstream-toorigin/dev dev 之后就同步了 A在dev分支写了iii,提交 B在dev分支写了hhh,提交,冲突 怎么修改,B把云端的拉下来,随便改改就行

YOLOv7 | 添加GSConv,VoVGSCSP等多种卷积,有效提升目标检测效果,代码改进(超详细)

⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/QdCj6 YOLOv7专栏&#xff1a; http://t.csdnimg.cn/dy…

Qt 多元素控件

Qt开发 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别 以 QTableWidget 和 QTableView 为例. QTableView 是基于 MVC 设计的控件. QTableView 自身不持有数据. 使用QTableView 的 …

latex如何让标题section取消数字标号

解决方法——加一个*号 在LaTeX中&#xff0c;如果你想让section标题取消数字标号&#xff0c;可以使用section*代替section。section*将生成一个不带数字标号的节标题。 例如&#xff0c;你可以这样写&#xff1a; \section*{这是不带数字标号的节标题}这将生成一个标题&am…

给老婆整了个短剧搜索机器人APP

最近短剧挺火&#xff0c;很多群友们都在做一些资源分享&#xff0c;老胡于是基于这些资源做了个短剧搜索引擎&#xff0c;挺多朋友喜欢看的&#xff0c;我老婆也在看哈哈&#xff0c;真上头&#xff0c;废话不多说&#xff0c;上短剧机器人。 短剧机器人 直接在微信群输入&…

解决由于历史原因解析tflite失败的问题

文章目录 0. 背景1. tflite 历史遗留问题2. schema3. flatbuffers 编译器3.1 安装 FlatBuffers 编译器3.2. 编译 FlatBuffers schema 文件3.3 使用生成的 Python 文件 4 问题未解决终极解决方案 写在最前面&#xff1a;解决方法是升级tensorflow版本&#xff0c;重新生成tflite…

【go从入门到精通】if else 条件控制

Go 语言条件语句&#xff1a; 在 Go 语言中&#xff0c;条件语句用于根据不同的条件执行不同的代码。Go 语言提供了两种条件语句&#xff1a;if 语句和switch 语句。 if语句 if由一个布尔表达式后紧跟一个或多个语句组成。 语法 Go 编程语言中 if 语句的语法如下&#xff…

反向海淘系统中的数据安全挑战与解决方案探讨

**反向海淘系统中的数据安全挑战与解决方案探讨** **一、背景** 随着反向海淘市场的不断扩大&#xff0c;涉及的数据安全挑战也日益增多。本文旨在探讨反向海淘系统中面临的数据安全挑战&#xff0c;以及相应的解决方案。 **二、数据安全挑战** 1. **数据传输安全**&#x…

微信支付宝--充ChatGPTPLUS/openAI key

ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见的模式和统计规律&#xff0c;来生成回答&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写论文、邮件、脚本、文案、翻译、代码等…
最新文章