c语言要点摘录(15~20)

十五.编译过程

        file.c,file.h经过预处理器处理成为file.i,再经过编译器(gcc)成为汇编file.s,再经过汇编器(as)成为file.o,最后通过连接器(linker)成为可执行文件。

       预处理器:1.处理所有的注释,以空格代替

                             2.将所有的#define删除,并展开所有定义的宏

                             3.处理条件编译指令,#if,#ifdef,#elif,#else,#endif

                             4.处理#include,展开被包含的文件

                             5.保留编译器需要使用的#pragma指令

    指令为:gcc -E file.c  -o   hello.i,得到预处理器处理完后的文件


     编译器     : 对预处理文件进行一系列的词法分析,语法分析,和语义分析,分析结束后进行代码优化,生成相应的汇编代码

    指令为:gcc -S file.c -o  hello.s

    汇编器       :将汇编代码转变成为可执行的指令。

   指令为:gcc -c  file.s  -o  hello.o

   连接器        :把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接,静态链接在编译期完成,动态链接在运行期完成。

  

十六.宏定义与使用分析

         宏可以定义在代码的任何地方,之后的代码都可以使用。

         宏表达式与函数的对比:

          1.宏表达式在预编译器被处理(单纯的展开),编译器不知道宏表达式的存在

          2.宏表达式用“实参”完全代替形参,不进行任何运算,任何字符都可以替换,应用更广

          3. 宏表达式没有任何调用开销

          4.宏表达式中不能出现递归定义

个宏比

一个宏比函数强的例子:

#define  DIM(array)   (sizeof(array)/sizeof(*array))第一个array代表数组

int dim(int array[])
{
  return sizeof(array)/sizeof(*array);//第一个array是指针
}

在这个求数组长度的例子中,宏由于是直接替换,所以没问题,但是 数组名做函数参数直接就会退化成为指针,返回值就不正确了(指针所占位数/数组第一个元素的内存位数,32位返回1,64位返回2)。


内置宏:

           

十七.条件编译使用分析


         可以在进行编译的时候指定程序需要使用的宏定义,来进行预处理展开,-D定义宏   -U取消宏

          #include 本质是将文件内容嵌入当前文件,所以被包含的文件应当使用#ifndef……#define……#endif,防止重复包含

十八.#error和#line指示字

         #error用于生成一个编译错误消息,并停止编译

                   用法:#error  message(message不需要双引号)

         #warning类似作用  


          #line 用于强制指定新的行号和编译文件名,并对源程序的代码重新编号,新的行号从下一行开始。用于指定自己的代码,现在可以用更先进的版本控制以及静态库和动态库来解决多人编码

          用法:#line  number  filename(filename可以省略)


十九.#pragma预处理分析

         #pragma是编译器指示字,用于指示编译器完成一些特定的动作。

         #pragma 所定义的很多指示字是编译器和操作系统特有的,在不同的编译器间是不可移植的

         #pragma:   预处理器会忽略不认识的#pragma指令并删除,并将认识的指令留给编译器来处理


       #pragma message:编译时输出消息到编译输出窗口,可用于代码的版本控制,VC特有,GCC将会忽略

内存对齐:

       为什么:cpu对内存读取不是连续的,而是分块读取的,块的大小只能是1,2,4,8,16字节

                      当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣

                      某些硬件平台只能从规定的地址处取某些特定类型的数据,否则会抛出硬件异常     


#pragma pack能够改变编译器的默认对齐方式   

       struct占用内存大小计算方法:


       gcc默认为4个字节对齐

      不能使用memcmp函数判断结构体是否相等,因为memcmp是使用内存进行判断,结构体使用前不清零,即使重新赋相同的值,每个内存地址里的值也不一定相同,另外一个原因就是因为对齐,有些内存地址是未定义的。


二十.#和##运算符

        #运算符是预处理指令开始符,比如#include<>

        #运算符用于在预编译期将宏参数转换为字符串

  

#include <stdio.h>

#define CONVERS(x) #x

int main()
{
    
    printf("%s\n", CONVERS(Hello world!));
    printf("%s\n", CONVERS(100));
    printf("%s\n", CONVERS(while));
    printf("%s\n", CONVERS(return));

    return 0;
}
输出结果:Hello world!
                 100
                 while
                 return
  

  ##   用于在预编译期粘连两个符号        

#include <stdio.h>

#define NAME(n) name##n

int main()
{
    
    int NAME(1);
    int NAME(2);
    
    NAME(1) = 1;
    NAME(2) = 2;
    
    printf("%d\n", NAME(1));
    printf("%d\n", NAME(2));

    return 0;
}

输出:1

          2

预处理器把NAME(1)替换成name1,NAME(2)替换成name2


用处:定义结构体类型。

     

#include <stdio.h>

#define STRUCT(type) typedef struct _tag_##type type;\
struct _tag_##type

STRUCT(Student)
{
    char* name;
    int id;
};

int main()
{
    
    Student s1;
    Student s2;
    
    s1.name = "s1";
    s1.id = 0;
    
    s2.name = "s2";
    s2.id = 1;
    
    printf("%s\n", s1.name);
    printf("%d\n", s1.id);
    printf("%s\n", s2.name);
    printf("%d\n", s2.id);

    return 0;
}

高效整洁的定义结构体,用于高通平台。



    




      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值