c语言预处理指令详解

//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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值