C语言学习入门到精通之gcc编译与调试

来源:互联网 发布:百合体验知乎 编辑:程序博客网 时间:2024/05/21 10:45

在linux系统下进行C语言开发的学习

    在linux系统下,C语言的编译是由gcc编译器(即释译工具)完成的

    arm-linux-gcc 是arm的编译器即编译的是运行在arm开发板上的程序

    arm-android-gcc 是android的编译器

   
    参数:

         -o    指定生成的目标

         -E   预处理 即把所有的带#的编译指令替换为标准C (预处理指令不是标准C指令)   gcc -o test.i  -E test.c  //  -E 预处理  -o 目标文件

</pre>         -S   编译成汇编     gcc  -o test.s -S test.i    <p></p><p>         -c   编译机器码 (机器码:即机器语言)    gcc  -o  test.o  -c  test.s</p><p>         gcc   -o    test    test.o    //-o   目标为可执行程序, .o为依赖的机器码文件   </p><p>     三合一    直接生成.o</p><p>     gcc   -o  test.o -c  test.c  </p><p>     四合一</p><p>     gcc   -o  test  test.c  </p><p>     注意: 在将.o文件(机器码)编译成可执行程序的过程还包含一个链接的过程,在编写应用程序的情况下,把这一块封装了,在后面的博客中会进一步的详细的描述 。 </p><p></p><h3>多文件的编程与编译</h3><p>     多文件编程指的是: main(即入口函数)在一个.c 文件中,在这一个.c 中需要使用其它.c 中的函数或数据,那么其它.c文件需要提供.h文件作为接口。特别是在模块化开发时更应该使用多文件编程的方式开发。</p><p>     1).h 的写法</p><p>          </p><pre name="code" class="cpp">#ifndef 宏名      //假设 该宏名没有定义,则编译下面代码#define 宏名     //定义宏    扩展声明#endif             //结束编译条件    宏名的规范写法: 头文件的名称的大写 . 变成 _    例如:头文件名称是:helle.h   则宏名可以使 HELLO_H
     2)声明和扩展声明

        

int max(int x.int y);    //函数的声明int main(int argc,char **argv){    int a=12;    int b=23;    int c=max(a,b);  //函数的调用}int max(int x,int y)  //函数定义{    return x>y?x:y;}

     3)静态声明以及扩展声明

          static 修饰函数,代表这个函数只能在本文档中使用  (使用条件:不希望该函数被其它.c文件所调用,只是对外提供接口)

          不用static 修饰的函数,代表全局函数,可以在任意文件中使用,但在编译时会找不到该函数,所以需要使用extern 作外部声明(在.h文件中)   

例子;//fun.h#ifndef FUN_H#define FUN_Hextern int max(int x,int y);  //扩展声明#endif//fun.cint max(int x,int y) //函数定义{    return x>y?x:y;}//test.c#include<stdio.h>#include"fun.h" //引入头文件(编译时会进行替换-extern int max(int x,int y);  )int mian(itn argc,char **argv){    int a;    int b=23;    int c=max(a,b);}

程序的调试

1、代码错误

     (1)语法错误(哈哈  自己解决吧!!!   在这我也没办法一一指出,在后续的博客更新中,我会贴上我自己代码编写过程中遇到的语法错误)

     (2)找不到.h文件 

              1)在.c文件中,#include“目录/头文件”

              2)编译时用 -I 来指定头文件位置              gcc -o test test.c  ./lib/fun.c   -I  ./lib      


2.段错误

      (1)参数需要的是内存地址,而给到的是其它类型          例 :scanf("%d %d",&a,b);

      (2)定义了一个指针变量 ,而指针变量中没有赋地址值

             

     int *p;     scanf("%d",p);
         注意:通常定义一个指针变量后,一定使用malloc或new 分配内存进而初始化或者使用NULL进行初始化,在释放malloc或mew分配的内存后,一定使用NULL对该指针变赋值
      

3、编译或运行出错的调试方法
  1)printf打印法

   int main(int argc,char *argv[]){
       printf("--------------- 1\n");
       int a=12;
       int b=0;
       printf("--------------- 2  a=%d,b=%d\n",a,b);
       int c=a/b;
       printf("--------------- 3\n");
       printf("---- %d\n",c);
       printf("--------------- 4\n");
   }
   程序员常用方法 如果2打印,而3未打印,则代表2与3之间出现错误
         
 2)调试工具法
   编译时必须用 -g参数编译,然后用gdb调试,如下:
        gcc -g -o test test.c fun.c
        gdb ./test
   当进入gdb后可使用如下指令
        l [n][fun] 查看代码  
        例:  l 查看所有代码  
                 l 3 查看第三行周围的代码  
                 l max 查看max函数
        b [文件名:][n][fun] 设置断点  
        例:  b 3 在第三行设置断点  
                 b max 在函数max处设置断点
        r 从前向后运行  遇到断点处停止
        p 打印信号     
       
        n 单步执行 不会进入函数
        u 单步执行 可跳出循环
        s 单位步执行,可以进入函数内部
           
        例:p a 打印变量a的值
               p &a 打印a的地址
               p a+2 打印变量a加2后的值
        info break 查看断点信息

     注意:我个人更加喜欢printf调试方法,不解释

      ps:在嵌入式方面遇到的问题,希望大家能够与我一起进行讨论共同进步,个人邮箱:983177739@qq.com(只能留个QQ邮箱,虽然比较low,但不惧垃圾邮件,哈哈,因为垃圾邮件已经够多了)



0 0