C语言编译链接(个人笔记)

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

第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
在这里插入图片描述

1.翻译环境

初略分为:
在这里插入图片描述

细分:
在这里插入图片描述

翻译环境可分为编译和链接,而编译又可分为预编译,编译,汇编,在预编译中编译器所操作的有头文件的展开,注释的删除,#define定义的符号替换,而编译时会生成一个.s后缀的文件,将C语言代码翻译成汇编代码,所用的到的规则有语法,词法,语义分析,还有符号汇总(就是将函数名之类汇总),而汇编阶段会将.s后缀的文件变为.o后缀的文件,将汇编代码转换成二进制的指令,形成符号表(将函数名之类的符号和地址联系在一起),链接阶段就是将每一个.o的文件链接起来,形成合并段表,符号表的合并和重定位(将每个.o文件的符号表链接起来),最后生成test.exe文件

在这里插入图片描述

下面解释一下为什么会有预处理,编译,汇编,实际上就是计算机语言发展的逆过程
在这里插入图片描述

2.运行环境

程序执行的过程:

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

预处理

1.预处理的符号

__FILE__      //进行编译的源文件
__LINE__     //文件当前的行号
__DATE__    //文件被编译的日期
__TIME__    //文件被编译的时间
__STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义
printf("file:%s line:%d\n", __FILE__, __LINE__);

2.宏和函数对比

宏通常被应用于执行简单的运算。
比如在两个数中找出较大的一个。

#define MAX(a, b) ((a)>(b)?(a):(b))

那为什么不用函数来完成这个任务?
原因:

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

宏的缺点:
3. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序
的长度。
4. 宏是没法调试的。
5. 宏由于类型无关,也就不够严谨。
6. 宏可能会带来运算符优先级的问题,导致程容易出现错。

3.#undef

这条指令用于移除一个宏定义。

#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

4.条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
比如说:调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译

#include <stdio.h>
#define __DEBUG__
int main()
{
     int i = 0;
     int arr[10] = {0};
     for(i=0; i<10; i++)
     {
         arr[i] = i;
         #ifdef __DEBUG__
             printf("%d\n", arr[i]);//为了观察数组是否赋值成功。 
         #endif //__DEBUG__
     }
     return 0;
 }
4.1比较常见的条件编译指令
1.
#if 常量表达式
 //...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
 //..
#endif
2.多个分支的条件编译
#if 常量表达式
 //...
#elif 常量表达式
 //...
#else
 //...
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
    #ifdef OPTION1
        unix_version_option1();
    #endif
    #ifdef OPTION2
        unix_version_option2();
    #endif
#elif defined(OS_MSDOS)
    #ifdef OPTION2
        msdos_version_option2();
    #endif
#endif

5.文件包含

#include 指令可以使另外一个文件被编译。就像它实际出现于 #include 指令的地方
一样。
这种替换的方式很简单:
预处理器先删除这条指令,并用包含文件的内容替换。
这样一个源文件被包含10次,那就实际被编译10次。
所以就可能会出现重复包含的情况
在这里插入图片描述
如何解决重复包含的问题呢?条件编译

//每个头文件的开头写:
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif   //__TEST_H__

//或者
#pragma once

笔试题

#define INT_PTR int*
typedef int* int_ptr
INT_PTR a,b;
int_ptr c,d;
//结果就是a,c,d是int* ,b是int型的
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

索隆43

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值