• 程序的编译和链接


     

    目录

    翻译环境 

    linux下的测试 ​编辑

    预定义符号

    执行环境

    #define定义宏

    #和##

    #

    ##

    宏参数的副作用

    宏和函数对比

    优点

    缺点

    #undef 

     条件编译

    头文件包含


    在标准c的任何实现中,存在两种环境——翻译环境和执行环境

    翻译环境 

    翻译环境生成目标文件(.obj)

    linux下的测试 

    预定义符号

    1. __FILE__      //进行编译的源文件
    2. __LINE__     //文件当前的行号
    3. __DATE__    //文件被编译的日期
    4. __TIME__    //文件被编译的时间
    5. __STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义

    vs不完全支持c标准,Linux下的gcc支持c标准。 

    执行环境

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

    #define定义宏

    #define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏 或定义宏
    #define name( parament-list ) stuff
    其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中。
    注意:参数列表的 左括号必须与name紧邻
    如果两者之间有任何空白存在,参数列表就会被解释为 stuff 的一部分。
    1. #define SQUARE(X) X*X//err
    2. SQUARE(5+1)--->5+1*5+1
    3. //正确写法:
    4. #define SQUARE(X) ((X)*(X))
    注意:
    1. 宏参数和 #define 定义中可以出现其他 #define 定义的符号(优先替换)。但是对于宏,不能出现递归
    2. 当预处理器搜索 #define 定义的符号的时候,字符串常量的内容并不被搜索
    1. #define SQUARE(X) ((X)*(X))
    2. #define X 2//正确

    #和##

    #

    当我们想实现下面这串代码时:

    1. int a = 10;
    2. printf("the value of a is %d\n", a);
    3. int b = 20;
    4. printf("the value of b is %d\n", b);
    5. float f = 3.5f;
    6. printf("the value of f is %f\n", f);

    有没有什么更简介的办法呢?

    我们知道,c语言可以对字符串进行拼接,比如:

    1. printf("hello" "world");
    2. //输出helloworld,省略了中间的空格。

    修改后:

    1. #define PRINT(val,format) printf("the value of "#val "is " format "\n",val)
    2. int a = 10;
    3. PRINT(a, "%d");
    4. int b = 20;
    5. PRINT(b, "%d");
    6. float f = 3.5f;
    7. PRINT(f, "%f");

    这里的#val相当于先对val完成替换再使之成为一个字符串("a")

    ##

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

    宏参数的副作用

    如果宏的参数在宏的定义中出现超过一次的话,如果参数带有副作用,将会导致不可预测的结果。

    1. #define MAX(x,y) ((x)>(y)?(x):(y))
    2. int main()
    3. {
    4. int a = 3;
    5. int b = 4;
    6. int m = MAX(++a, ++b);
    7. int m = ((++a) > (++b) ? (++a) : (++b));
    8. printf("m = %d a=%d b=%d\n", m, a, b);
    9. return 0;
    10. }

     输出结果为6,4,6

    宏和函数对比

    优点

            用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。 所以宏比函数在程序的规模和速度方面更胜一筹
            更为重要的是函数的参数必须声明为特定的类型。
    所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以 用于> 来比较的类型。

     

    1. #define MALLOC(type,num) (type)malloc(sizeof(type)*num)
    2. int* p = MALLOC(int*,4);//define实现自定义封装

    缺点

    1.宏不能调试。

    2.宏可能会带来运算符优先级问题。

    3.宏由于类型无关,可能会导致程序不严谨。

    4.如果宏定义的代码量过大,可能会大幅增加程序的长度

     

    #undef 

    作用:移去#define定义的对象

     

    命令行定义

    此方法适用于linux操作系统用命令的方式在程序编译的时候对未定义的变量进行定义的一种方式。 

    1. #include
    2. int main()
    3. {
    4.    int array [ARRAY_SIZE];
    5.    int i = 0;
    6.    for(i = 0; i< ARRAY_SIZE; i ++)
    7.   {
    8.        array[i] = i;
    9.   }
    10.    for(i = 0; i< ARRAY_SIZE; i ++)
    11.   {
    12.        printf("%d " ,array[i]);
    13.   }
    14.    printf("\n" );
    15.    return 0;
    16. }

     命令行:
    gcc test.c -D ARRAY_SIZE=10 

     条件编译

    在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件 编译指令

    常见的条件编译语句:

    1. #if 常量表达式
    2. //...
    3. #endif
    4. 2.多个分支的条件编译
    5. #if 常量表达式
    6. //...
    7. #elif 常量表达式
    8. //...
    9. #else
    10. //...
    11. #endif
    12. 3.判断是否被定义
    13. #if defined(symbol)
    14. #ifdef symbol
    15. #if !defined(symbol)
    16. #ifndef symbol
    17. 4.嵌套指令
    18. #if defined(OS_UNIX)
    19. #ifdef OPTION1
    20. unix_version_option1();
    21. #endif
    22. #ifdef OPTION2
    23. unix_version_option2();
    24. #endif
    25. #elif defined(OS_MSDOS)
    26. #ifdef OPTION2
    27. msdos_version_option2();
    28. #endif
    29. #endif

    与if..else很相似,不同的是条件编译会把不满足条件的代码在预处理阶段直接删除掉。 

    头文件包含


    本地文件包含:

    #include "filename"

    库文件包含:

    #include 

    嵌套包含:

    comm.h comm.c 是公共模块。
    test1.h test1.c 使用了公共模块。
    test2.h test2.c 使用了公共模块。
    test.h test.c 使用了 test1 模块和 test2 模块。
    这样最终程序中就会出现两份 comm.h 的内容。这样就造成了文件内容的重复

    解决方案:

    开头写:

    #prama once
    

    或者

    1. #ifndef __TEST_H__
    2. #define __TEST_H__
    3. //头文件的内容
    4. #endif

  • 相关阅读:
    【Linux】安装软件与运行程序
    Linux:ip:rx_dropped; 丢包
    HTML5图形绘制——canvas元素
    MySQL数据库设计规范及SQL规范
    突如其来的第一个1024要笑着过
    Clickhouse上用Order By保证绝对正确结果但代价是性能
    springboot+shiro+layuimini实现后台管理系统的权限控制(一)基础环境搭建
    传统行业 CRUD 六年,疫情期间备战一个月,三面阿里巴巴定级 P7
    【Windows 常用工具系列 11 -- 福昕PDF搜索高亮过的文本】
    利用frps搭建本地自签名https服务的透传
  • 原文地址:https://blog.csdn.net/dwededewde/article/details/133935551