集成开发环境(IDE,Integrated Development Environment )是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。
将所有的功能全部封装在一块,比如常用的VS。我们看不到程序的翻译过程,程序运行时直接就被翻译运行,显示结果了。
程序的翻译环境和执行环境:
翻译环境:源代码被转换为可执行的机器指令
执行环境:实际执行代码
翻译环境:
程序在编译过程中,程序的源文件会被转换成目标文件(windows为.obj,linux为.o文件),头文件在编译期间会进行包含展开。
编辑器(vim)—写代码
编译链接器(gcc)—将代码变为二进制
调试器(gdb)—调试器
这是在linux中,将各个工具都分开了。
程序在编译大致分为4个过程:
例如:
#define DOUBLE(N) N*2
int main()
{
int a=4;
printf("%d\n",DOUBLE(a));
return 0;//sample
}
在linux中,预处理操作指令为:
gcc -E test.c(文件名)-o test.i(转化文件名为临时文件)
查看该文件,宏被进行了替换,注释也被取消。预处理之后,还是C语言
gcc -S test.i -o test.s
gcc -c test.s -o test.o
c一定要为小写的
查看文件为:二进制乱码
此时,我们生成的二进制文件还不能进行运行,因为还未进行和库文件的链接。
gcc test.o -o mytest(任意名字)
运行环境:
预处理详解:
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵守ANSI C,其值为1,否则未定义
;
例如:这样一个代码
在执行的时候,就会发生错误。
预处理看一下:
在这里,a就携带了两个分号,这时就会出现语法错误。如果对ifelse
语句带上大括号,就不会有错。
替换规则:
- 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号,如果是,先被替换。
- 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
- 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,重复上述操作。
注意:
#和##:字符串有自动连接特性!
char *p = "hello ""world!\n";
printf("hello ""world!\n");
printf("%s", p);
#
,把一个宏参数变成对应的字符串。#define PRINT(FORMAT,VALUE) printf("the value of "#VALUE" is "FORMAT"\n",VALUE)
int i = 10;
PRINT("%d", i + 3);
#define ADD_TO_SUM(num,value) sum##num += value
int sum5 = 10;
ADD_TO_SUM(5, 10);
printf("%d\n", sum5);
要注意先定义,否则这样的标识符是没有定义的,就会报错。
在使用宏中,尽量不要使用带有副作用的参数,这个副作用会使表达式求值的时候出现永久性效果,出现的结果是不可预测的。
比如传入的参数为x++ x--
这样的,就会出现问题。
宏和函数相比较:
优势:
劣势:
在命名时,尽量将宏名全部大写,函数名不要全部大写。 易于区分二者。
宏从定义开始,往下都是有效的。 (宏在前,程序在后,后面的程序都可使用宏,宏前面的程序不行)
#undef :用于移除一个宏定义。
命令行定义:编译时定义宏。
指令为:gcc 文件名 -D 宏名和值
在linux中。
这样一个代码:
操作上述指令,结果为:
在编译一个相同程序的不同版本的时候,就可以用到这个特性。
条件编译: 根据条件,选择执行的语句。选择性编译。
常见的条件编译指令:
#if 常量表达式
#endif
#if 常量表达式
#elif 常量表达式
#elif 常量表达式
...
#endif
#if defined(宏名)
#ifdef 宏名 //前两个一样
#if !defined(宏名)
#ifndef 宏名 //后两个一样
文件包含: #include
指令可以使另一个文件被包含。在预处理阶段,先删除这段指令,并用包含文件的内容进行替换。
比如我们常用的#include
->会把头文件的相关内容直接插入到我们的源代码当中,替换掉#include
。
头文件被包含的方式:
#include “filename.h”
#include
对于库文件是否也可以用“”
的形式去查找?
可以这样做。但是这样做会使查找效率变低,也不容易区分是本地文件还是库文件。
怎么解决这个问题?
进行条件编译。
#ifndef __TEST_H__
#define __TEST_H__
#enif __TEST_H__
如果没有定义,对该宏进行定义,文件重复包含时,内容也不会重复。这里面的宏,尽量使用文件名。
一般我们使用头文件时,尽量加上这个条件编译。