您的位置:首页 > 编程语言 > C语言/C++

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

2016-05-30 12:36 423 查看

在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_H
extern int max(int x,int y);  //扩展声明
#endif

//fun.c
int 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
[fun] 查看代码  

        例:  l 查看所有代码  

                 l 3 查看第三行周围的代码  

                 l max 查看max函数

        b [文件名:]
[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,但不惧垃圾邮件,哈哈,因为垃圾邮件已经够多了)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息