首页 > 其他分享 >c语言预处理详解

c语言预处理详解

时间:2023-07-29 21:46:07浏览次数:43  
标签:__ 语言 int 定义 ++ 详解 printf 预处理 define

//extern int ADD(int x, int y);//声明引用外部文件
//c语言预处理
// 文本文件 翻译+链接 二进制文件 运行
//test.cpp————————》test.exe————————》
// 编译器 翻译环境 链接器 执行环境
// test.obj(目标文件)
//
//(linux系统)翻译器:
// gcc -E
// 预编译(test.i):把头文件放进文件里
// 删除注释(空格替换)
// #define 定义的进行替换
// gcc -S
// 编译(test.s):把c代码翻译成汇编代码
// (语法分析,词法分析,语义分析,符号汇总)
// gcc -c
//汇编(test.o):形成符号表
// 把汇编代码转换成二进制代码指令
// obj文件(目标文件) 二进制文件
//
// 链接器:
// 多个 .obj 文件通过链接器链接
// 合并段表(符号表):(固定格式分段) elf格式 多个程序分段形成符号表
// 符号表的合并和重定位: 多个符号表合并,
// 符号重定位(把一个文件内的声明的符号地址改成
// 另一个文件的实际有效地址),这样就链接起来了
//
//
// 运行环境:
// 程序必须载入内存中:有操作系统就由操作系统完成
// 独立环境中,程序需要手动安排,或可执行代码置入只读内存
// 程序开始执行,调用main函数
// 开始执行代码,使用一个运行时堆栈(stack),存储函数局部变量和返回地址,
// 同时可以使用静态(static)内存中的变量并在执行过程中一直保留他们的值
// 终止程序,正常终止,或意外终止
//
// 预处理详解:
// 预定义符号: __FILE__ 进行编译的源文件——当前文件的路径
// __LINE__ 文件当前的行号——当前代码的行号
// __DATE__ 文件被编译的日期
// __TIME__ 文件被编译的实际
// __STDC__ 如果编译器遵循ANSI C 值为1, 否则未定义
// ...
// 预处理指令:
// #define// 定义的静态值,可在程序中完成替换,不能在内容后面加;
// #include
// #pragma pack(4) 设置默认对齐数
// #pragma pack()
// #if
// #endif
// #error
// #line
// #开头定义的指令
//

//#define 定义标示符号 #define name stuff name名字 stuff内容
//#define MAX 100
//#define STR "HEHE"
//#define reg register//存储器关键字
//#define do_forever for(::)//用形象的符号替换一种函数实现
//#define CASE break:case//在case 语句后面自动把break写上
//#define DEBUG_PRINT printf("%s\n", __TIME__)//如果内容过长,每行加上 \ (续航符)


//#define定义宏
//#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)
// 定义宏(define macro)
// #define name(parament-list) stuff
// parament-list是参数列表,用逗号隔开
// 参数可以出现在suff里面注:左括号和name紧贴一起
// stuff内容根据符号优先级用()进行分装
//
// #define 替换规则
// 1;在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号;
// 发现有就进行替换。
// 2,替换文本随后被插入程序中的原文本位置,对于宏,参数名都会被他们的值替换
// 3,最后,再次扫描是否有#define定义的符号,发现有就再次替换
// 注意:
// 1:宏参数和#define可以出去其他#define定义的符号,但是宏不能递归
// 2:预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索
//
//
// #和##
// # 字符串常量化运算符 把宏参数插入到字符串中
// ## 合并粘贴运算符,可以把它两边的符号合成一个符号,
// 允许宏定义从分离的文本片段创建标识符
//
//
// 带有副作用的宏参数
//
// 函数有参数类型,宏没有参数类型
//
// #undef 取消宏定义
//
//
// 命令行定义
// 在程序执行时,许多编译器提供了允许在命令行中定义符号的功能(给程序中的变量赋值)
// 有的命令行有参数 有的没有
//
//
// 条件编译指令
// 选择性的对语句进行编译或者放弃,有条件的编译指令
// 1, #if 常量表达式
// #endif ——结束
//
// 2,#if 常量表达式 ---如果
// #elif 常量表达式 ——或如果
// #else 常量表达式 ——否则
// #endif ——结束
//
// 3,判断是否被定义
// #if defined(symbol)--如果定义了symbol
// #ifdef symbol 和上一句等价
//
// #if !defined(symbol) --如果没有定义symbol
// #ifndef symbol 和上一句等价
//
// #endif ---结束
// 4,嵌套指令
// #if defined(str1)//如果定义了str1
// #ifdef ptr1//如果定义了ptr1
// r1();//执行r1
// #endif ---内结束
// #ifdef ptr2//如果定义了ptr2
// r2();执行r2
// #endif ---内结束
// #elif defined(str2)//或如果定义了str2
// #ifdef ptr2//如果定义了ptr2
// r2();//执行r2
// #endif ---内结束
// #endif ---外结束
//
//
// 文件包含 #include
// 使另一个文件被编译,拷贝到当前文件里
// <库函数头文件> 在标准路径(安装路径)去查找
// "自编(本地)头文件"
// 查找策略:先查源文件所在目录下找,未发现就在标准位置(安装路径)查找,最后未发现提示编译错误
//
//
// 嵌套文件重复包含头文件解决方案
// 方案1, #ifndef __TEST_H__
// #define __TEST_H__
// (头文件内容)
// #endif
// 方案2,#pragma once
//

 

//含参数的宏定义
//#define MAX 100
//#define SQUARE(X) ((X)*(X))//stuff内容根据符号优先级用()进行分装

//#把宏定义参数插入字符串里
//void print(int x)
//{
// printf("the value of x is %d\n", x);//x是固定的,不能转换a或者b
//}
//#define PRINT(X) printf("the value of "#X" is %d\n", X)//多个字符串放在一起会自动连在一起

//##字符串粘连
//#define CAT(X,Y) X##Y//把X的内容和Y的内容连在一起

//宏定义参数中存在++ -- 等副作用参数
//#define MAX(X,Y) ((X)>(Y)?(X):(Y)) //给X,Y 的变量是直接整体替换的,不会进行计算
//#define 优势:预处理完成替换直接到判断语句,没有函数调用和返回的开销,更省时间,
// 宏没有参数类型(通用),还可以传(类型)参数
// 劣势:宏会直接将代码插入到程序中,如果宏很长,就会增加程序的长度
// 宏不能调试,没参数类型,不严谨
// 宏会有运算符优先级带来的副作用
//函数会有调用和返回的开销,且有函数参数类型要求

//#undef MAX 取消宏定义

//int Max(int x, int y)
//{
// return (x > y ? x : y);
//}

//#define DEBUG


int main()
{

int arr[10] = { 0 };
int i = 0;
int a = 10;
int b = 20;
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]);
}
int c = ADD(a, b);
printf("%d", c);
//printf("%s\n", __FILE__);//当前文件的路径
//printf("%d\n", __LINE__);//当前代码的行号
//printf("%s\n", __DATE__);
//printf("%s\n", __TIME__);
//printf("%d\n", __STDC__);VS是未定义这个的

//宏定义参数替换
int ret = SQUARE(5);//ret = 25;
ret = SQUARE(5 + 1);//ret = 11;宏是直接用5+1替换X,使用得到11,
//可以在宏定义用(X)进行分开成单独个体
ret = SQUARE(MAX);
printf("MAX= %d\n", MAX);//"MAX= %d\n"中的字符串MAX不会被#define检测替换

//#把宏参数插入到字符串中
int a = 10;
int b = 20;
print(a);
print(b);
PRINT(a);
printf("the value of "#X" is %d\n", X)
PRINT(b);

//##把字符串粘连在一起
//int abcd10 = 2019;
//printf("%d\n", CAT(abcd, 10));//abcd##10 == abcd10

//带有副作用的宏参数
int a = 10;
int b = 11;
int max = MAX(a++, b++);//++改变了a和b的值
max = ((a++)>(b++)?(a++):(b++))
// 这个代码执行:先比较a和b b大,然后a++,b++,再把b的赋值给max,最后b++
printf("%d\n", max);//12
printf("%d\n", a);//11
printf("%d\n", b);//13

//函数和宏比较
int a = 10;
int b = 11;
float c = 3.0f;
float d = 3.1f;
int max = MAX(a, b);
printf("%d\n", max);
max = Max(a, b);
printf("%d\n", max);
float max1 = MAX(c, d);

//条件编译
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = 0;
#ifdef DEBUG//如果DEBUG定义了,就执行printf
#if defined DEBUG//如果DEBUG定义了,就执行printf
#ifndef DEBUG//如果没有定义DEBUG
#if !defined DEBUG
printf("%d ", arr[i]);
#endif // DEBUG 结束条件编译


}

#if 1==0
printf("1\n");
#elif 2==2
printf("2\n");
#else
printf("3")

#endif

 

return 0;
}

标签:__,语言,int,定义,++,详解,printf,预处理,define
From: https://www.cnblogs.com/zrk-8008/p/17590594.html

相关文章

  • C语言中.与->的用法介绍
    (一)基础结构体用点,结构体指针用箭头。a->b 的含义是 (*a).b****。  现代的标准化的C语义上来说, -> 可以用 * 和 . 的组合实现。简单的说,就是一个快捷方式,一个语法糖。(二)例子在机器码和汇编的角度来看,不存在变量,不存在struct这种东西,只存在寄存器和一个叫做内存的大数......
  • C语言字符串的常用操作
    C语言是一种非常流行的编程语言,它支持各种数据类型,包括整数、浮点数、字符和字符串等。在C语言中,字符串是一种特殊的数据类型,它由一系列字符组成,以\0字符结尾。本文将介绍C语言中字符串的相关知识,包括字符串的定义、初始化、赋值、输入输出、比较、拼接、查找和替换等。一、字符......
  • nsq整体架构及各个部件作用详解
    文章目录        前言        nsq的整体架构图        部件:nsqd        部件:nsqlookupd        部件:nsq连接库        部件:nsqadmin 前言我们讲了nsq是什么,有什么用,它的内部组成部件,下载,单点搭建,集群搭建等等这一篇博客,我们开始......
  • 【C语言趣味教程】(4) 变量:代码注释 | 变量的声明 | 初始化与赋值 | 变量的命名 | 关
    Ⅰ.代码注释(Comment)0x00引入:注释的作用"程序员最讨厌两种人:一种是不写注释的人,一种是让我写注释的人。"相信大家对注释早已有所耳闻,对于注释,C语言有两种注释风格,我们下面会逐个讲解。 但在这之前,我们先来了解了解注释的作用,注释就是用于解释代码的文字的。注释通常用于版本、版......
  • 性能优化之详解各种指标
    前言上篇文章最后提到了我们可以通过performance的一些属性对性能做统计,我们会发现performance对象下有非常多的属性,远不止上篇文章提到的DOMContentLoaded与Load这两个事件。或许你在浏览器控制台见过它们这些身影:DCL、LCP、FP、FCP、L这里的DCL与L就是我们上篇文章介绍的DOMConte......
  • c语言作业之登录账号
    intmain(){ inti=0; charpassword[20]={0}; for(i=0;i<3;i++) { printf("请输入密码:>"); scanf("%s",password); //if(password=="123456");//err,==不能用来比较两个字符串是否相等,应该使用一个库函数strcmp if(strcmp(password,......
  • Centos8 中文语言配置支持
    安装中文语言包如果不知道中文语言包,使用以下命令查看[09:39:51]root@ive:~#yumsearchChinese加载插件"osmsplugin"失败:Nomodulenamed'librepo'上次元数据过期检查:0:26:02前,执行于2023年07月29日星期六09时14分49秒。==================================......
  • c语言学习第一课
    VS工具提前输入#define_CRT_SECURE_NO_WARNINGS1数据类型char //字符数据类型short//短整型int  //整型long //长整型longlong //更长整型float //单精度浮点数double //双精度浮点数 printf(“%lf\n",d);   lf表示双精度浮点数类型用来向内存申请空间创......
  • VsCode如何配置C语言环境?
    以前学校上C语言课程都是使用VC++6.0上课,这个学期为了复习一遍C语言,而且自己经常使用VSCode开发前端项目,所以为了方便。这里把需要的环境和插件配置在这里介绍一下。Windows环境下安装C语言编译器MinGW-W64GCCC的下载地址为:https://sourceforge.net/projects/mingw-w64/下载......
  • 快读快写 原理详解
    快读快写原理详解目录快读快写原理详解代码快读readquickly快写writequickly代码解释快读第一部分第二部分第三部分第四部分第五部分快写第一部分第二部分第三部分第四部分第五部分参考文献C++的cincout和C的scanfprintf等IO函数已经够我们是用了,但是它们很慢,......