精华内容
下载资源
问答
  • C语言编译程序

    2013-03-15 20:21:55
    初学者可以用的c语言编译程序,更容易对一些初学者进行练习
  • Tiny C语言编译程序之词法分析Scanner

    千次阅读 2017-05-22 21:58:58
    Tiny C语言编译程序之词法分析Scanner约定: 仅允许整数类型,不允许实数类型 标识符由大小写英文字母组成,最多52个。其识别按最长匹配原则 整数后紧跟非数字,或标识符后紧跟非字母认为是一个新Token开始 由{ }括...

    Tiny C语言编译程序之词法分析Scanner

    约定:

    • 仅允许整数类型,不允许实数类型
    • 标识符由大小写英文字母组成,最多52个。其识别按最长匹配原则
    • 整数后紧跟非数字,或标识符后紧跟非字母认为是一个新Token开始
    • 由{ }括起来符号串都认为是注释部分,该部分在词法分析时被过滤掉
    • 识别出的Token由两个变量:currentToken,tokenString识别,其中currentToken代表Token的类属,为一个名为TokenType的枚举类型,在文件globals.h中定义;tokenString代表Token在程序中出现的形式,即其本来面目。例如整数10的currentToken值为NUM,而tokenString值为‘10’;标识符i的currentToken值为ID,而tokenString值为‘i’

    画识别符合TINY C语言构词规则的DFA。然后用直接编码的方法构造词法分析器

    词法分析器scan.c

    /****************************************************/
    /* File: scan.c                                     */
    /* The scanner implementation for the TINY compiler */
    /****************************************************/
    
    #include "globals.h"
    #include "util.h"
    #include "scan.h"
    
    /* states in scanner DFA */
    typedef enum
       { START,INASSIGN,INCOMMENT,INNUM,INID,DONE }
       StateType;
    
    /* lexeme of identifier or reserved word */
    char tokenString[MAXTOKENLEN+1];
    
    /* BUFLEN = length of the input buffer for
       source code lines */
    #define BUFLEN 256
    
    static char lineBuf[BUFLEN]; /* holds the current line */
    static int linepos = 0; /* current position in LineBuf */
    static int bufsize = 0; /* current size of buffer string */
    static int EOF_flag = FALSE; /* corrects ungetNextChar behavior on EOF */
    
    /* getNextChar fetches the next non-blank character
       from lineBuf, reading in a new line if lineBuf is
       exhausted */
    //获得下一字符
    static int getNextChar(void)
    { if (!(linepos < bufsize))
      { lineno++;
        if (fgets(lineBuf,BUFLEN-1,source))
        { if (EchoSource) fprintf(listing,"%4d: %s",lineno,lineBuf);
          bufsize = strlen(lineBuf);
          linepos = 0;
          return lineBuf[linepos++];
        }
        else
        { EOF_flag = TRUE;
          return EOF;
        }
      }
      else return lineBuf[linepos++];
    }
    
    /* ungetNextChar backtracks one character
       in lineBuf */
    //用于回吐字符
    static void ungetNextChar(void)
    { if (!EOF_flag) linepos-- ;}
    
    /* lookup table of reserved words */
    //定义保留字表
    static struct
        { char* str;
          TokenType tok;
        } reservedWords[MAXRESERVED]
       = {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
          {"repeat",REPEAT},{"until",UNTIL},{"read",READ},
          {"write",WRITE}}; 
    
    /* lookup an identifier to see if it is a reserved word */
    /* uses linear search */
    //进行保留字的匹配
    static TokenType reservedLookup (char * s)
    { int i;
      for (i=0;i<MAXRESERVED;i++)
        if (!strcmp(s,reservedWords[i].str))
          return reservedWords[i].tok;
      return ID;
    }
    
    /****************************************/
    /* the primary function of the scanner  */
    /****************************************/
    /* function getToken returns the 
     * next token in source file
     */
    TokenType getToken(void)
    {  /* index for storing into tokenString */
       /* tokenString的索引*/
       int tokenStringIndex = 0;
       /* holds current token to be returned */
       /* 保存当前要返回的符号 */
       TokenType currentToken;
       /* 当前的状态——总是从START开始 */
       /* current state - always begins at START */
       StateType state = START;
       /* 是否保存到tokenString的标记 */
       /* flag to indicate save to tokenString */
       int save;
       while (state != DONE)
       { int c = getNextChar();
         save = TRUE;
         switch (state)
         { case START:
             if (isdigit(c))
               state = INNUM;
             else if (isalpha(c)) /*(字符、:、空格/tab/换行、{、算符及界符等)*/
                state = INID;
             else if (c == ':')
                state = INASSIGN;
             else if ((c == ' ') || (c == '\t') || (c == '\n'))
                save = FALSE;
             else if (c == '{')
             {
                save = FALSE;
                state = INCOMMENT;
             }
             else
             {
                state = DONE;
                switch(c)
                {
                    case EOF:
                        save = FALSE;
                        currentToken = ENDFILE;
                        break;
                    case '=':
                        currentToken = EQ;
                        break;
                    case '<':
                        currentToken = LT;
                        break;
                    case '+':
                        currentToken = PLUS;
                        break;
                    case '-':
                        currentToken = MINUS;
                        break;
                    case '*':
                        currentToken = TIMES;
                        break;
                    case '/':
                        currentToken = OVER;
                        break;
                    case '(':
                        currentToken = LPAREN;
                        break;
                    case ')':
                        currentToken = RPAREN;
                        break;
                    case ';':
                        currentToken = SEMI; 
                        break;
                    default:
                        currentToken = ERROR;
                        break;
                }
             }
             break;
           case INCOMMENT:
             /* 仅出现‘}’或EOF(注释未完结束程序)时才改变状态。 */
             save = FALSE;
             if (c == '}')
             {
                state = START;
             }else if (c == EOF)
             {
                state = DONE;
                currentToken = ENDFILE;
             }
             break;
           case INASSIGN:
             /* ‘=’或其它(出现错误) */
             state = DONE;
             if(c == '=')
                currentToken = ASSIGN;
             else
             {
                ungetNextChar();
                save = FALSE;
                currentToken = ERROR;
             }
             break;
           case INNUM:
             if (!isdigit(c))
             { /* backup in the input */
               ungetNextChar();
               save = FALSE;
               state = DONE;
               currentToken = NUM;
             }
             break;
           case INID:
             /* 不是字符则回吐,并进入DONE,且识别出一个ID */
             if (!isalpha(c))
             { /* backup in the input */
               ungetNextChar();
               save = FALSE;
               state = DONE;
               currentToken = ID;
             }
             break;
           case DONE:
           default: /* should never happen */
             fprintf(listing,"Scanner Bug: state= %d\n",state);
             state = DONE;
             currentToken = ERROR;
             break;
         }
         if ((save) && (tokenStringIndex <= MAXTOKENLEN))
           tokenString[tokenStringIndex++] = (char) c;
         if (state == DONE)
         { tokenString[tokenStringIndex] = '\0';
           if (currentToken == ID)
             currentToken = reservedLookup(tokenString);
         }
       }
       if (TraceScan) {
         fprintf(listing,"\t%d: ",lineno);
         printToken(currentToken,tokenString);
       }
       return currentToken;
    } /* end getToken */
    
    

    对于Tiny语言编写的Sample程序源代码如下:

    { Sample program
      in TINY language -
      computes factorial
    }
    read x; { input an integer }
    if 0 < x then { don't compute if x <= 0 }
      fact := 1;
      repeat
        fact := fact * x;
        x := x - 1
      until x = 0;
      write fact  { output factorial of x }
    end

    词法分析主要为后面的各个阶段提供方法getToken;经过词法分析后每行的关键字、标识符以及数字如下:

    TINY COMPILATION: SAMPLE.tny
       1: { Sample program
       2:   in TINY language -
       3:   computes factorial
       4: }
       5: read x; { input an integer }
            5: reserved word: read
            5: ID, name= x
            5: ;
       6: if 0 < x then { don't compute if x <= 0 }
            6: reserved word: if
            6: NUM, val= 0
            6: <
            6: ID, name= x
            6: reserved word: then
       7:   fact := 1;
            7: ID, name= fact
            7: :=
            7: NUM, val= 1
            7: ;
       8:   repeat
            8: reserved word: repeat
       9:     fact := fact * x;
            9: ID, name= fact
            9: :=
            9: ID, name= fact
            9: *
            9: ID, name= x
            9: ;
      10:     x := x - 1
            10: ID, name= x
            10: :=
            10: ID, name= x
            10: -
            10: NUM, val= 1
      11:   until x = 0;
            11: reserved word: until
            11: ID, name= x
            11: =
            11: NUM, val= 0
            11: ;
      12:   write fact  { output factorial of x }
            12: reserved word: write
            12: ID, name= fact
      13: end
            13: reserved word: end
            14: EOF

    备注

    内容为课堂所学及网上参考,仅供参考.

    展开全文
  • Tiny C语言编译程序之语法分析Parser

    千次阅读 2017-05-22 22:09:59
    Tiny C语言编译程序之语法分析Parser约定: 用递归下降分析法,为每个语法符号编写子程序。进入每个子程序前已读入一个新Token。 一个语法结构的内部表示形式为语法树,数据结构是globals.h中的treeNode。在做语法...

    Tiny C语言编译程序之语法分析Parser

    约定:

    • 用递归下降分析法,为每个语法符号编写子程序。进入每个子程序前已读入一个新Token。
    • 一个语法结构的内部表示形式为语法树,数据结构是globals.h中的treeNode。在做语法分析的同时建立语法结构的内部表示——语法树。

    语法分析器parse.c

    /****************************************************/
    /* File: parse.c                                    */
    /* The parser implementation for the TINY compiler  */
    /****************************************************/
    
    #include "globals.h"
    #include "util.h"
    #include "scan.h"
    #include "parse.h"
    
    static TokenType token; /* holds current token */
    
    /* function prototypes for recursive calls */
    static TreeNode * stmt_sequence(void);  /* 语句序列 */
    static TreeNode * statement(void);      /* 语句 */
    static TreeNode * if_stmt(void);        /* if语句 */ 
    static TreeNode * repeat_stmt(void);    /* 循环语句 */ 
    static TreeNode * assign_stmt(void);    /* 赋值语句 */
    static TreeNode * read_stmt(void);      /* 输入语句 */
    static TreeNode * write_stmt(void);     /* 输出语句 */
    static TreeNode * exp(void);            /* 表达式 */
    static TreeNode * simple_exp(void);     /* 简单表达式 */
    static TreeNode * term(void);           /* 乘法项 */
    static TreeNode * factor(void);         /* 因子 */
    
    /* 显示出错信息*/
    static void syntaxError(char * message)
    { fprintf(listing,"\n>>> ");
      fprintf(listing,"Syntax error at line %d: %s",lineno,message);
      Error = TRUE;
    }
    
    /* 保存向前看记号的静态变量token和检测输入的记号是否和预期相同 */
    static void match(TokenType expected)
    { if (token == expected) token = getToken();/*它找到匹配时就调用getToken,否则就声明出错*/
      else {
        syntaxError("unexpected token -> ");
        printToken(token,tokenString);
        fprintf(listing,"      ");
      }
    }
    
    /* 用来匹配非终结符stmt_sequence */
    TreeNode * stmt_sequence(void)
    { TreeNode * t = statement();
      TreeNode * p = t;
      while ((token!=ENDFILE) && (token!=END) &&
             (token!=ELSE) && (token!=UNTIL))/* 当输入的记号不标识语句序列结束的记号 */ 
      { TreeNode * q;
        match(SEMI);/* 跳过分号 */
        q = statement();
        if (q!=NULL) {
          if (t==NULL) t = p = q;
          else /* now p cannot be NULL either *//* 如果t不是NULL,那么p也一定不是NULL */
          { p->sibling = q;/* 把state链接起来 */
            p = q;
          }
        }
      }
      return t;
    }
    
    /* 用来匹配statement非终结符 */
    TreeNode * statement(void)
    { TreeNode * t = NULL;
      switch (token) {/* 检测当前的token,根据输入决定如何识别 */
        case IF : t = if_stmt(); break;
        case REPEAT : t = repeat_stmt(); break;
        case ID : t = assign_stmt(); break;
        case READ : t = read_stmt(); break;
        case WRITE : t = write_stmt(); break;
        default : syntaxError("unexpected token -> ");
                  printToken(token,tokenString);
                  token = getToken();
                  break;
      } /* end case */
      return t;
    }
    
    /* 用来匹配if_stmt非终结符 */
    TreeNode * if_stmt(void)
    {             
        TreeNode * t = newStmtNode(IfK);
        match(IF);
        if (t!=NULL) 
            t->child[0] = exp();
        match(THEN);
        if (t!=NULL) 
            t->child[1] = stmt_sequence(); 
        if (token==ELSE) {
            match(ELSE);
            if (t!=NULL) 
                t->child[2] = stmt_sequence();
        }
        match(END);
        return t;
    }
    
    /* 用来匹配repeat_stmt非终结符 */
    TreeNode * repeat_stmt(void)
    {   
        TreeNode * t = newStmtNode(RepeatK);
        match(REPEAT);
        if(t!=NULL){
            t->child[0] = stmt_sequence(); 
        }
        match(UNTIL);
        if(t!=NULL){
            t->child[1] = exp();
        }
        return t;
    }
    
    /* 用来匹配assign_stmt非终结符 */
    TreeNode * assign_stmt(void)
    { 
        TreeNode * t = newStmtNode(AssignK);
        if((t!=NULL)&&(token==ID)){
            t->attr.name = copyString(tokenString);
        }
        match(ID);
        match(ASSIGN);
        if(t!=NULL){
            t->child[0] = exp();
        }
        return t;
    }
    
    /* 用来匹配read_stmt非终结符 */
    TreeNode * read_stmt(void)
    {
        TreeNode * t = newStmtNode(ReadK);
        match(READ);
        if((t!=NULL)&&(token==ID)){
            t->attr.name = copyString(tokenString);
        }
        match(ID);
        return t;
    }
    
    /* 用来匹配write_stmt非终结符 */
    TreeNode * write_stmt(void)
    {
        TreeNode * t = newStmtNode(WriteK);
        match(WRITE);
        if(t!=NULL){
            t->child[0] = exp();
        }
        return t;
    }
    
    /* 用来匹配exp非终结符 */
    TreeNode * exp(void)
    { TreeNode * t = simple_exp();
      if ((token==LT)||(token==EQ)) {
        TreeNode * p = newExpNode(OpK);
        if (p!=NULL) {
          p->child[0] = t;
          p->attr.op = token;
          t = p;
        }
        match(token);
        if (t!=NULL)
          t->child[1] = simple_exp();
      }
      return t;
    }
    
    /* 用来匹配simple_stmt非终结符 */
    TreeNode * simple_exp(void)
    {
        TreeNode * t = term();
        while ((token==PLUS)||(token==MINUS)){ 
            TreeNode * p = newExpNode(OpK);
            if (p!=NULL) {
                p->child[0] = t;
                p->attr.op = token;
                t = p;
                match(token);
                t->child[1] = term();
            }
        }
        return t;
    }
    
    /* 用来匹配term非终结符 */
    TreeNode * term(void)
    {
        TreeNode * t = factor();
        while ((token==TIMES)||(token==OVER)){
            TreeNode * p = newExpNode(OpK);
            if (p!=NULL){
                p->child[0] = t;
                p->attr.op = token;
                t = p;
                match(token);
                p->child[1] = factor();
            }
        }
        return t;
    }
    
    /* 用来匹配factor非终结符 */
    TreeNode * factor(void)
    {
        char msgerror[100];
        TreeNode * t = NULL;
        switch (token) {
            case NUM :
                t = newExpNode(ConstK);
                if ((t!=NULL) && (token==NUM)){
                    t->attr.val = atoi(tokenString);    
                }
                match(NUM);
                break;
            case ID :
                t = newExpNode(IdK);
                if ((t!=NULL) && (token==ID)){
                    t->attr.name = copyString(tokenString); 
                }
                match(ID);
                break;
            case LPAREN :
                match(LPAREN);
                t = exp();
                match(RPAREN);
                break;
            default:
                strcpy(msgerror,"unexpected token -> ");
                strcat(msgerror,tokenString);
                syntaxError(msgerror);
                //syntaxError("unexpected token -> ");
                //printToken(token,tokenString);
                token = getToken();
                break;
        }
        return t;
    }
    
    /****************************************/
    /* the primary function of the parser   */
    /****************************************/
    /* Function parse returns the newly 
     * constructed syntax tree
     */
    TreeNode * parse(void)
    { TreeNode * t;
      token = getToken();
      t = stmt_sequence();
      if (token!=ENDFILE)
        syntaxError("Code ends before file\n");
      return t;
    }

    分析后输出的语法树结构如下:

    Syntax tree:
      Read: x
      If
        Op: <
          Const: 0
          Id: x
        Assign to: fact
          Const: 1
        Repeat
          Assign to: fact
            Op: *
              Id: fact
              Id: x
          Assign to: x
            Op: -
              Id: x
              Const: 1
          Op: =
            Id: x
            Const: 0
        Write
          Id: fact
    展开全文
  • c语言学习大全 包括c语言学习教程 C语言开发小程序 c语言开发案例 和经典编程900例 绝对是你学习C语言程序设计的好帮手。
  • 我们编译原理快学完了,想自己动手写c语言编译程序(只完成 分析到生成中间代码部分) 我应该如何入手写这个东西,查阅什么资料,反正有什么建议或者能帮助我完成的,给我说说就好
  • 请在win xp 系统或 windows sever 2003系统下运行vc6 c++编译程序,否则可能出现为止错误!
  • C语言编译中,什么时候应该使用32位编译程序? 32位编译程序应该在32位操作系统上使用。由32位编译程序生成的32位程序比16位程序运行得更快,这正是任何32位的东西都很热门的原因。 有那么多不同版本的Microsoft ...
    C语言编译中,什么时候应该使用32位编译程序?
    32位编译程序应该在32位操作系统上使用。由32位编译程序生成的32位程序比16位程序运行得更快,这正是任何32位的东西都很热门的原因。
    有那么多不同版本的Microsoft Windows,它们和哪种编译程序组成最佳搭配呢?

    Windows 3.1和Windows for Workgroups 3.11是16位的操作系统;Microsoft Visual C++1.x是16位编译程序,它所生成的程序能在Windows 3.1上运行。Microsoft Windows NT和Windows 95是32位操作系统;Microsoft Visual C++2.o是32位编译程序,它所生成的32位程序能在这两种操作系统上运行。由Visual C++1.x生成的16位程序不仅能在Windows 3.1上运行,也能在Windows NT和Windows 95上运行。

    然而,由Visual 2.O生成的32位程序无法在Windows 3.1上运行。这就给Microsoft提出了一个难题——它希望每个人都使用它的32位编译程序,但是有6千万台计算机所使用的Windows版本无法运行32位程序。为了克服这个障碍,Microsoft设计了一个叫做Win32s的转换库,用来完成由32到16位的转换,从而使由Visual C++生成的32位程序能在
    Windows 3.1和Windows for Workgroups上运行。Win32s是专门为在Windows 3.1(和WFW)上运行而设计的,它不能用在Windows NT和Windows 95上,因为它们不需要为运行32位程序作什么转换。有了Win32s,你就可以用Visual C++2.0生成一个既能在Windows 3.1(和WFW)上运行,又能在Windows NT上运行的程序了。

    最后还有一个问题,即编译程序本身的问题。Visual C++1.x是一个16位Windows程序,它既能在Windows 3.1上运行并生成16位程序,也能在Windows 95和Windows NT上运行并生成同样的程序。但是,作为一个32位程序,Visual C++2.O无法在Windows 3.1上运行,即使装上了Win32s也无法运行,因为出于方便的目的,Microsoft认为在启动Visual C++2.O之前,你一定运行在Windows 95或Windows NT上。

    总而言之,在Windows 3.1,Windows for Workgroups,Windows 95或Windows NT上运行Visual c++1.x(更新的版本为1.51)而生成的16位程序能在任何版本的Windows上运行。由Visual C++2.O生成的32位程序在Windows 95或Windows NT上运行得很快,但它在Windows 3.1(和WFW)下也能很好地运行。

    对于Borland C/C++,Borland的Turbo C++3.1版是版本较新的16位编译程序,Borland c++4.5版(注意该名称中没有"Turbo一词)是32位Windows编译程序。这两种编译程序都包含编译程序、Borland的OWL C++类和一个出色的集成化调试程序。


    展开全文
  • 使用C语言进行简单的程序编译,上手简单,方便初学者理解C语言编程,此文件为简单的C语言循环编译通过输出*来构建心形
  • C语言编译过程详解

    2019-03-07 23:02:56
    本文以Linux下C语言编译过程为例,讲解C语言程序编译过程。 编写hello world C程序: // hello.c #include &lt;stdio.h&gt; int main(){ printf("hello world!\n"); } 编译过程只需: ...

    前言

    C语言程序从源代码到二进制行程序都经历了那些过程?本文以Linux下C语言的编译过程为例,讲解C语言程序的编译过程。

    编写hello world C程序:

    // hello.c
    #include <stdio.h>
    int main(){
        printf("hello world!\n");
    }
    

    编译过程只需:

    $ gcc hello.c # 编译
    $ ./a.out # 执行
    hello world!

    这个过程如此熟悉,以至于大家觉得编译事件很简单的事。事实真的如此吗?我们来细看一下C语言的编译过程到底是怎样的。

    上述gcc命令其实依次执行了四步操作:1.预处理(Preprocessing), 2.编译(Compilation), 3.汇编(Assemble), 4.链接(Linking)。

     

    示例

    为了下面步骤讲解的方便,我们需要一个稍微复杂一点的例子。假设我们自己定义了一个头文件mymath.h,实现一些自己的数学函数,并把具体实现放在mymath.c当中。然后写一个test.c程序使用这些函数。程序目录结构如下:

    ├── test.c
    └── inc
        ├── mymath.h
        └── mymath.c
    

    程序代码如下:

    // test.c
    #include <stdio.h>
    #include "mymath.h"// 自定义头文件
    int main(){
        int a = 2;
        int b = 3;
        int sum = add(a, b); 
        printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
    }

    头文件定义:

    // mymath.h
    #ifndef MYMATH_H
    #define MYMATH_H
    int add(int a, int b);
    int sum(int a, int b);
    #endif

    头文件实现:

    // mymath.c
    int add(int a, int b){
        return a+b;
    }
    int sub(int a, int b){
        return a-b;
    }

    1.预处理(Preprocessing)

    预处理用于将所有的#include头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。gcc的预处理是预处理器cpp来完成的,你可以通过如下命令对test.c进行预处理:

    gcc -E -I./inc test.c -o test.i

    或者直接调用cpp命令

    $ cpp test.c -I./inc -o test.i

    上述命令中-E是让编译器在预处理之后就退出,不进行后续编译过程;-I指定头文件目录,这里指定的是我们自定义的头文件目录;-o指定输出文件名。

    经过预处理之后代码体积会大很多:

    X 文件名 文件大小 代码行数
    预处理前 test.c 146B 9
    预处理后 test.i 17691B 857

    预处理之后的程序还是文本,可以用文本编辑器打开。

    2.编译(Compilation)

    这里的编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。编译的指定如下:

    $ gcc -S -I./inc test.c -o test.s

    上述命令中-S让编译器在编译之后停止,不进行后续过程。编译过程完成后,将生成程序的汇编代码test.s,这也是文本文件,内容如下:

    // test.c汇编之后的结果test.s
        .file   "test.c"
        .section    .rodata
    .LC0:
        .string "a=%d, b=%d, a+b=%d\n"
        .text
        .globl  main
        .type   main, @function
    main:
    .LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        subl    $32, %esp
        movl    $2, 20(%esp)
        movl    $3, 24(%esp)
        movl    24(%esp), %eax
        movl    %eax, 4(%esp)
        movl    20(%esp), %eax
        movl    %eax, (%esp)
        call    add 
        movl    %eax, 28(%esp)
        movl    28(%esp), %eax
        movl    %eax, 12(%esp)
        movl    24(%esp), %eax
        movl    %eax, 8(%esp)
        movl    20(%esp), %eax
        movl    %eax, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret 
        .cfi_endproc
    .LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
        .section    .note.GNU-stack,"",@progbits

    请不要问我上述代码是什么意思!-_-

    3.汇编(Assemble)

    汇编过程将上一步的汇编代码转换成机器码(machine code),这一步产生的文件叫做目标文件,是二进制格式。gcc汇编过程通过as命令完成:

    $ as test.s -o test.o

    等价于:

    gcc -c test.s -o test.o

    这一步会为每一个源文件产生一个目标文件。因此mymath.c也需要产生一个mymath.o文件

    4.链接(Linking)

    链接过程将多个目标文以及所需的库文件(.so等)链接成最终的可执行文件(executable file)

    命令大致如下:

    $ ld -o test.out test.o inc/mymath.o ...libraries...

    结语

    经过以上分析,我们发现编译过程并不像想象的那么简单,而是要经过预处理、编译、汇编、链接。尽管我们平时使用gcc命令的时候没有关心中间结果,但每次程序的编译都少不了这几个步骤。也不用为上述繁琐过程而烦恼,因为你仍然可以:

    $ gcc hello.c # 编译
    $ ./a.out # 执行

    参考文献

    1.https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
    2.http://www.trilithium.com/johan/2005/08/linux-gate/
    3.https://gcc.gnu.org/onlinedocs/gccint/Collect2.html

     

    文章内容转载自:https://www.cnblogs.com/CarpenterLee/p/5994681.html

    展开全文
  • C语言编译过程

    千次阅读 2018-04-01 12:14:06
    C语言编译过程为:预处理--&gt;编译--&gt;汇编--&gt;链接1、预处理(Pre-processing) 对源程序中的伪指令(以#开头的指令)和特殊符号进行处理。伪指令包括:宏定义指令、条件编译指令、头文件包含...
  • C语言程序编译过程

    千次阅读 2014-06-08 20:03:09
    C语言编译过程
  • C语言程序编译步骤

    2020-07-27 14:25:43
    C语言代码编译程序经过4步: 1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里并不会检查语法。 2)编译:检查语法,将预处理后文件编译生成汇编文件。 3)汇编:将汇编文件生成目标...
  • 请编写程序计算该函数对任一输入整数的值。 输入格式: 输入在一行中给出整数n。 输出格式: 在一行中按照格式“sign(n) = 函数值”输出该整数n对应的函数值。 输入样例1: 10 输出样例1: sign...
  • C语言编译预处理

    千次阅读 2019-08-05 08:18:43
    C语言由源代码生成可执行程序的过程如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 其中编译预处理阶段,读取C源程序,对其中的预处理指令(以#开头的...
  • C语言编译执行过程

    千次阅读 2019-09-27 10:14:57
    一、C语言的编译执行过程 我们在C语言编辑的文件是以.c为文件拓展名...编译程序本身-->优化程序-->汇编程序-->链接程序-->可执行文件 二、编译执行过程详解 第一步:在编辑器中编辑源文件 第...
  • c语言编译过程详解

    2017-06-29 11:11:52
    本文以Linux下C语言编译过程为例,讲解C语言程序编译过程。 编写hello world C程序:// hello.c #include int main(){ printf("hello world!\n"); } 编译过程只需: $ gcc hello.c # 编译 $ ./a.out # 执行...
  • C语言编译全过程

    千次阅读 2015-10-05 23:16:54
    C语言编译全过程  编译的概念:编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求...
  • 家庭财务管理系统—可执行程序(c语言编译——结构体) 希望对你有所帮助
  • 在主程序里有一段点亮发光二极管的代码,和一段计数器计数并在数码管上显示的代码。同时工作时,二极管正常点亮,数码管几秒才点亮一回,而且十位显示是闪烁一下就不显示了 2.数码管显示时,位选和段选顺序不能改变...
  • 基于Ubuntu的C语言编译以及Makefile方式编译准备工作安装gccgcc编译编写一个主程序文件main1.c和子程序文件sub1.c新建文件main1.c新建文件sub1.c用gcc编译文件运行代码makefile编程新建文件makefile编译makefile运行...
  • C语言编译步骤

    2017-03-25 11:15:49
    C语言从代码变成可执行程序的步骤: 预处理 -----> 编译 -----> 汇编 -----> 链接 ⒈预处理:去掉注释,加载头文件,代替宏定义,条件编译 需要文件:.c文件 生成产物:预处理文件(以.i结尾) ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,234
精华内容 8,093
关键字:

c语言编译程序

c语言 订阅