zoukankan      html  css  js  c++  java
  • gcc学习笔记

    1:第一个程序 : hello world

    #include <stdio.h>

    int main(void)

    {

      printf("Hello , world ! ");

      return 0;

    }

    编译: gcc -Wall hello.c -o hello

     

     

    2:调试错误 :  debug.c

     

    #include <stdio.h>

    int main(void)

    {

      printf("Two plus two is %f ", 4);

      return 0;

    }

    编译: gcc -Wall hello.c -o hello

    错误 1: 乱码  解决: export LANG=c

    然后可以提示代码中的错误

     

     

    3:拆分程序

    将hello.c拆分成3个文件

     

    hello1.c  自定义函数定义

    hello.h 自定义函数声名文件

    main.c  主文件

     

     

    hello1.c 

    #include <stdio.h>

    void hello(const char* string)

    {

         printf(string);

    }

     

    hello.h

    #include <stdio.h>

    void hello(const char* string); 

     

    main.c

    #include <stdio.h>

    #include "hello.h"

    int main(void)

    {

         hello("hello world ");

         return 0;

    }

     

     

    编译多个文件 : gcc -Wall main.c hello1.c -o newhello

     

    4 :Verbose Compilation

    主要用于调试程序,显示程序编译的详细信息

    格式 : gcc -v -Wall  hello.c -o hello

     

     

     

    5: 独立编译

    每个.c文件独立编译成一个.o(windows中obj文件),最后通过链接器(linker)成为一个可执行文件。只用重新编译修改的文件。

    格式:  gcc -Wall -c main.c        gcc -Wall -c hello1.c

    此时会生成目标文件(与源文件同名,扩展名.o)

    链接器: gcc main.o hello1.o -o bbk

     

     

    6:Make的作用

          只编译修改过的文件生成.o文件,对于没有更新过的源文件则不重新编译

     

     

    7:Linking With External Libraries

          系统库不需要显式声明

         例:

          #include <math.h>

          #include <stdio.h>

            int main(void)

            {

            double m;

            scanf("%L",&m);

            double x = sqrt(m);

            printf("The square root of 2.0 is %f ", x);

            return 0;

            }

            老版本的编译器需要显式声明: 

        

          gcc -Wall main.c /usr/lib/libm.a -o calc

           同: gcc -Wall main.c -lm -o calc

           注: -lNAME   等价于连接库文件  libNAME.a (标准目录下,不是当前目录)

     

    8:  Common Problem In compiling 

         header files or library file is (头文件和库文件的默认路径):

        /usr/local/include/

        /usr/include/

     

        /usr/local/lib  g

        /usr/lib

     

        调用用户的头文件 

       1: gcc -Wall -I/usr/myheaerdir -L./ -lmy.a (推荐方法)  -I 设置头文件的路径,-L库文件目录

       2: 通过shell设置环境变量 ,变量名: C_INCLUDE_PATH    LIBRARY_PATH

       3:修改环境变量

        

    9:Create a Library with ar 

         通过ar 命令将一堆的目标文件(.o文件)连接成一个库文件(.a文件),然后主文件连接此库文件

        格式: ar cr libNAME.a file1.o file2.o .... filen.o

        

       根据库文件,查看连接的目标文件 

       格式: ar t libmy.a  

     

    例:

    mylib.h

    int func1(int x, int y);

    void func2(int x);

     

    fun1.c

    #include "mylib.h"

    int func1(int x, int y)

    {

    return (x+y);

    }     

     

    fun2.c

    #include<stdio.h>

    #include "mylib.h"

    void func2(int x)

    {

        printf("the int is %d ", $x);

    }

     

    maina.c

    #include<stdio.h>

    #include "mylib.h"

    int main(void)

    {

       int i ;

        i = func1(1,2);

        func2(i);

        return 0;

    }

     

    操作顺序: 

    1:gcc -Wall -c fun1.c   //生成目标文件

    2:gcc -Wall -c fun2.c

    3:ar cr libhello.a fun1.o fun2.o  //将两个目标文件生成1个库文件libhello.a

    4:gcc -Wall maina.c libhello.a -o hello  (注意maina.c放在库文件的前面,遵循先调用后定义的原则 ,将maina.c编译成目标文件后,用3个目标文件编译可忽略次序问题

    )

    同:gcc -Wall main.c -L. -lhello -o h3  ("L"设置库文件的韦当前目录,"l"库文件名)

     

     

     

    设置系统的环境变量:

    1:查看系统的环境变量   env | grep LIB

    2:设置系统的全局变量   export LIBRARY_PATH=/usr/local/gcc:$LIBRARY_PATH

     

    调整程序目录为 

    include目录    mylib.h

    lib目录            libhello.a

    mina.c

    编译: gcc -Wall maina.c -Iinclude -Llib -lhello -o h4

     

    查看库文件由哪些目标文件合成:

    ar t libhello.a

     

    研究Apache的源码

     

     

     

    10:Shared Vs Static Library (动态库、静态库)

    动态库,windows下dll文件   linux下so文件 

    可执行文件执行时,先加载动态库到内存,动态库可被多个可执行文件共离

     

    将动态库放到系统的标准目录/usr/local/lib  /usr/lib

    设置系统变量 LB_LIBRARY_PATH

     

     

     

    11:C的版本

     

       标准C、Gcc支持的特殊方式

     

    例:ansi.c

    #include <stdio.h>

    int main(void)

    {

    const char asm[] = '6705';

    printf("the string asm is '%s' ", asm);

    return 0;

    }

    gcc -Wall ansi.c -o an

    直接编译会报错,原因:asm不是标准C的关键词,是gcc支持C 的关键字

    修正: gcc - Wall -ansi ansi.c -o an 

     

    例2:pi.c

    #include <math.h>

    #include <stdio.h>

    int main(void)

    {

     printf("the value of pi is %f ", M_PI);

     return 0;

    }

    gcc - Wall -ansi pi.c -o pi c

    将会报错,原因:宏M_PI 在标准C中没有定义,Gcc支持

    gcc -Wall pi.c -o pi

    解决办法:编译时,调用Gnu的宏定义

    gcc -Wall -ansi -D_GNU_SOURCE pi.c -o pp

     

     

    例3:严格C标准  v.c

    #include <stdio.h>

    int main(int argc, char* argv[])

    {

        int i, n = argc;

        double x[n];

        for(i = 0; i < n ; i++)

        {

            x[i] = i;

        }

        printf("result is %l ", x);

        return 0;

    }

     

    gcc -Wall -ansi -pedantic v.c -o v  // 两个选项,强制按照C标准

    以上会报错,标准C不支持可变长的数组 

    gcc -Wall v.c -o v

     

    -Wall的相关选项

    1:注释问题,嵌套注释的错误   -Wcomment

         解决方法:外层注释用宏定义

        #if 0

                /* 被注释掉的内容 */

        #endif 

     

    2: -Wunused

        声明但未使用的变量

     

     

     

     

     

     

    12: Using the Preprocessor  预处理(替换代码中的宏定义等操作)

    例:    

    dtest.c

    #include <stdio.h>

    int main(void)

    {

    #ifdef TEST

        printf("Test mode ");

    #endif

        printf("Running... ");

        return 0;

    }

     

    gcc -Wall -DTEST=456 dtest.c -o dt  //编译时定义一个宏,默认值为1

    查看系统的宏定义: cpp -dM /dev/null

    -D 编译时定义宏

    -E  只预处理程序,不编译 (只替换源文件中的include和宏定义)

    -save-temp   编译时,保存预处理后的结果(.i文件和.s文件)  .i  => .s =>.o 

    例:

    hello1.c

    #include <stdio.h>

    int main(void)

    {

      printf("Hello , world ! ");

      return 0;

    }

     

    gcc -Wall -c -save-temps hello1.c 

     

     

    13: Compiling for Debugging

        可执行文件中只包含机器码,不利于调试。调试模式可保存行号等信息

        当程序意外终止,将产生一堆'core'文件  (ulimit -c unlimited 设置不限制dump文件大小,默认不允许产生dump文件)

        用gdb对core进行调试

        -g 选项以调试模式来编译源代码(将行号等信息保存在可执行文件中)

    例:null.

    #include <stdio.h>

    int a (int *p);

    int main(void)

    {

        int* p = 0;

        return a(p);

    }

    int a(int *p)

    {

        int y = *p;

        return y;

    }

    程序bug:指针p指针地址为0的内存空间(系统核心的地址),将报错

     

    调试: gcc -Wall -g null.c  (-g选项 用于调试用,将源码中的相关信息保存在最终的可执行文件中)

    执行程序: ./a.out (提示错误,程序 core dumped; 同时产生错误日志core.)

    将产生core文件,通过gdb可调试此出错的文件

    命令:gdb a.out core.989  (此时可查看到相关的错误信息)

    gdb中可用的简单操作:

    print p       (打印变量)

    backtrace   (返回上一步的调用 )

     

    14: Compiling with Optimization

       gcc会根据不同的CPU自动优化代码;

       Source-level Optimization 

        源码层次的优化

       1:CSE (公共子进程优化)

       例:

       x = cos(v) * (1 + sin(u/2)) + sin(w) * (1 - sin(u/2))

       优化为:

       t = sin(u/2);

       x = cos(v) * (1 + t) +sin(w) * (1 - t)   

       2: Function Inlining  (FL)

       对于频繁调用的函数,执行入栈、出栈操作比较频繁,效率低,可将函数声明为inling function

       例:

     inling double sq(double x)

       {

           return (x * x);

       }

    sum = 0.0;

    for(i = 0; i< 1000000; i++)

    {

        sum += sq(i + 0.5);  //调用函数过程:将当前地址入栈,转到函数地址,执行完函数再出栈

    }

    人为优化:

    t = i + 0.5;

    sum += t *t;

    注:当优化开头打开时,会自动对代码进行优化;或者人为的知道函数调用频率高,可将函数声明为inline函数;

     

     

     

    15: Loop Unrolling (speed-space tradeoff)

    每循环一次,都要判断是否结束,增加开销;

    例: 

    for(i = 0 ; i< 8; i++)

    {    

        y[i] = i;

    }

    简单优化:

    y[0] = 0;

    y[1] = 1;

    y[2] = 2;

    y[3] = 3;

    y[4] = 4;

    y[5] = 5;

    y[6] = 6;

    y[7] = 7;

     

    16:Scheduling 

      并行执行 指令,编译执行时间长,不会增大可执行文件大小及内存

     

    17:Optimization level

        优化等级, 指令: -oLEVEL // level is a number from 0 to 3

        -o0 用于debug

        -o2 用于生产环境

      

      test.c

      #include <stdio.h>

      double powern(double d, unsigned n)

    {

        double x = 1.0;

        unsigned j;

        for(j=0; j<n; j++)

            x *=d;

        return x;

    }

    int main(void)

    {

        double sum = 0.0;

        unsigned i;

        for(i=1; i< 100000000; i++)

        {

            sum += powern(i, i%5);

        }

        printf("sum = %g ", sum);

        return 0;

    }

     

    gcc -Wall -o0 test.c -o test0 

    查看执行时间  time ./test0

    gcc -Wall -o3 -funroll-loops test.c -o test4  //for循环优化

     

     

    Gcc常用总结:

    参数
    -I (大写i) 头文件路径
    -L 库文件路径
    -l 库文件名称 (-lmy 等价 libmy.a)
    -o 生成可执行文件
    -c 编译单个文件为目标文件
    -W 错误级别
    -v 显示编译过程中的详细信息

    将目标文件生成库文件
    ar cr libabc.a file1.o file2.o file3.o
    查看库文件包含的目标文件
    ar t libabc.a 

  • 相关阅读:
    Confluence未授权模板注入/代码执行(CVE-2019-3396)
    Python实现批量处理扫描特定目录
    windows10 缺失 msvcp140.dll 解决办法
    nessus 故障处理
    python 处理json数据
    python 实现两个文本文件内容去重
    python3 实现多域名批量访问特定目录(一)
    python 简单的实现文件内容去重
    python 实现爬取网站下所有URL
    php强大的filter过滤用户输入
  • 原文地址:https://www.cnblogs.com/dormscript/p/4825320.html
Copyright © 2011-2022 走看看