程序的编译和链接

目录

翻译环境

[linux下的测试 ​编辑](#linux下的测试 编辑)

预定义符号

执行环境

#define定义宏

#和##

#

##

宏参数的副作用

宏和函数对比

优点

缺点

#undef

条件编译

头文件包含


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

翻译环境

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

linux下的测试

预定义符号

cpp 复制代码
__FILE__      //进行编译的源文件
__LINE__     //文件当前的行号
__DATE__    //文件被编译的日期
__TIME__    //文件被编译的时间
__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 的一部分。

cpp 复制代码
#define SQUARE(X) X*X//err
SQUARE(5+1)--->5+1*5+1
//正确写法:
#define SQUARE(X) ((X)*(X))

注意:

  1. 宏参数和 #define 定义中可以出现其他 #define 定义的符号(优先替换)。但是对于宏,不能出现递归
  2. 当预处理器搜索 #define 定义的符号的时候,字符串常量的内容并不被搜索
cpp 复制代码
#define SQUARE(X) ((X)*(X))
#define X 2//正确

#和##

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

cpp 复制代码
	int a = 10;
    printf("the value of a is %d\n", a);

	int b = 20;
	printf("the value of b is %d\n", b);

	float f = 3.5f;
	printf("the value of f is %f\n", f);

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

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

cpp 复制代码
printf("hello"  "world");
//输出helloworld,省略了中间的空格。

修改后:

cpp 复制代码
#define PRINT(val,format) printf("the value of "#val  "is " format "\n",val)
int a = 10;
PRINT(a, "%d");
	
int b = 20;
PRINT(b, "%d");
	
float f = 3.5f;
PRINT(f, "%f");

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

可以把位于它两边的符号合成一个符号。

它允许宏定义从分离的文本片段创建标识符

宏参数的副作用

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

cpp 复制代码
#define MAX(x,y) ((x)>(y)?(x):(y))

int main()
{
	int a = 3;
	int b = 4;
	int m = MAX(++a, ++b);

	int m = ((++a) > (++b) ? (++a) : (++b));
	printf("m = %d a=%d b=%d\n", m, a, b);

	return 0;
}

输出结果为6,4,6

宏和函数对比

优点

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

cpp 复制代码
#define MALLOC(type,num) (type)malloc(sizeof(type)*num)

int* p = MALLOC(int*,4);//define实现自定义封装

缺点

1.宏不能调试。

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

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

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

#undef

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

命令行定义

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

cpp 复制代码
#include <stdio.h>
int main()
{
    int array [ARRAY_SIZE];
    int i = 0;
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        array[i] = i;
   }
    for(i = 0; i< ARRAY_SIZE; i ++)
   {
        printf("%d " ,array[i]);
   }
    printf("\n" );
    return 0;
}

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

条件编译

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

常见的条件编译语句:

cpp 复制代码
#if 常量表达式
 //...
#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

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

头文件包含

本地文件包含:

cpp 复制代码
#include "filename"

库文件包含:

cpp 复制代码
#include <stdio.h>

嵌套包含:


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

开头写:

cpp 复制代码
#prama once

或者

cpp 复制代码
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
相关推荐
TeYiToKu几秒前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
dsywws3 分钟前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
互联网打工人no17 分钟前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒10 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
yeyuningzi11 分钟前
Debian 12环境里部署nginx步骤记录
linux·运维·服务器
羊小猪~~13 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
上辈子杀猪这辈子学IT29 分钟前
【Zookeeper集群搭建】安装zookeeper、zookeeper集群配置、zookeeper启动与关闭、zookeeper的shell命令操作
linux·hadoop·zookeeper·centos·debian
洋24034 分钟前
C语言常用标准库函数
c语言·开发语言
minihuabei34 分钟前
linux centos 安装redis
linux·redis·centos
EasyCVR1 小时前
萤石设备视频接入平台EasyCVR多品牌摄像机视频平台海康ehome平台(ISUP)接入EasyCVR不在线如何排查?
运维·服务器·网络·人工智能·ffmpeg·音视频