C语言预处理
C 预处理器是一个文本替换工具
所有的预处理器命令都是以井号(#)开头。下面列出了所有重要的预处理器指令:
指令 描述
#define 定义宏
#include包含一个源代码文件
#undef 取消已定义的宏
#ifdef 如果宏已经定义,则返回真
#ifndef 如果宏没有定义,则返回真
#if 如果给定条件为真,则编译下面代码
#else #if 的替代方案
#elif 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
#endif 结束一个 #if……#else 条件编译块
#error 当遇到标准错误时,输出错误消息
#pragma 使用标准化方法,向编译器发布特殊的命令到编译器中
================================================================
分块记忆为
define undef
if elif else endif
ifdef endif
ifndef endif
error
pragma
================================================================
C提供的三种预处理(gcc -E)功能:
文件包含
条件编译
宏定义
-------------------------------------------------------------
什么是宏?
宏就是替换。
宏定义末尾不加分号
-------------------------------------------------------------
宏定义是C提供的三种预处理功能的其中一种,这三种预处理包括:宏定义、文件包含、条件编译
宏定义又称为宏代换、宏替换,简称“宏”。
格式:
#define 标识符 字符串
其中的标识符就是所谓的符号常量,也称为“宏名”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。
掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。
即在对相关命令或语句的含义和功能作具体分析之前就要换:
例:
#define PI 3.1415926
把程序中出现的PI全部换成3.1415926
说明:
(1)宏名一般用大写
(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;
(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
(6)可以用#undef命令终止宏定义的作用域
(7)宏定义不可以嵌套
(8)字符串" "中永远不包含宏
(9)宏定义不分配内存,变量定义分配内存。
(10)宏定义不存在类型问题,它的参数也是无类型的。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
C 内存管理
C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。
1 void *calloc(int num, int size);该函数分配一个带有 num 个元素的数组,每个元素的大小为 size 字节。
2 void free(void *address);该函数释放 address 所指向的h内存块。
3 void *malloc(int num);该函数分配一个 num 字节的数组,并把它们进行初始化。
4 void *realloc(void *address, int newsize);该函数重新分配内存,把内存扩展到 newsize。
=================================================================
简记:
alloc(allocate)分配
* mallac()
* calloc(num,size);
* realloc(*address,int newsize);
void free(*address);
=================================================================
Linux下对编译后的可执行文件Test使用size命令,结果如下:
size Test
text data bss dec hex filename
1197 504 16 1717 6b5 Test
可以看出,此可执行程序在存储时(没有调入到内存)分为代码区(text)、数据区(data)和未初始化数据区(bss)3个部分。
栈和堆的区别
栈是由编译器在需要时分配的,不需要时自动清除的变量存储区。里面的变量通常是局部变量、函数参数等。堆是由malloc()函数(C++语言为new运算符)分配的内存块,内存释放由程序员手动控制,在C语言为free函数完成(C++中为delete)
C程序执行时的内存分配情况如注释所述:
//main.cpp
int a = 0; //a在全局已初始化数据区
char *p1; //p1在BSS区(未初始化全局变量)
main()
{
int b; //b在栈区
char s[] = "abc"; //s为数组变量,存储在栈区,
//"abc"为字符串常量,存储在已初始化数据区
char *p1,p2; //p1、p2在栈区
char *p3 = "123456"; //123456\0在已初始化数据区,p3在栈区
static int c =0; //C为全局(静态)数据,存在于已初始化数据区
//另外,静态数据会自动初始化
p1 = (char *)malloc(10);//分配得来的10个字节的区域在堆区
p2 = (char *)malloc(20);//分配得来的20个字节的区域在堆区
free(p1);
free(p2);
}