C语言代码区错误

欲想了解C语言代码段会有如何错误,我们必须首先了解编译器是如何把C语言文本信息编译成为可以执行的机器码的。

背景介绍

  • 测试使用的C语言代码

    • 导入标准库,定义宏变量,定义结构体,重命名结构体,
    • 函数原型声明,主函数入口,函数定义
#include <stdio.h>

#define PI 3.14159

typedef struct student {
char name[8];
int age;
} Student; void sayHi(Student); int main() {
// we define a Student structure here.
Student mushroom = {"mushroom", 19};
/*
Output some massage.
*/
sayHi(mushroom);
printf("I know PI equels to %lf", PI);
return 0;
} void sayHi(Student stu) {
printf("Hi! I am %s.\n", stu.name);
}
  • C语言编译基本流程

  • 一共划分为了文件输入,预处理,编译,汇编,连接,最后输出为可执行文件。GCC正好就为我们提供了所有的这些方法,下面来一一介绍下GCC内置的处理C语言文件的指令。
  • GCC编译器基本指令了解

指令名 解释
gcc -c 编译或汇编源文件,但是不作连接.编译器输出对应于源文件的目标文件.
gcc -S 编译后即停止,不进行汇编.对于每个输入的非汇编语言文件,输出文件是汇编语言文件.
gcc -E 预处理后即停止,不进行编译.预处理后的代码送往标准输出.
gcc -o filename 指定输出文件为file.该选项不在乎GCC产生什么输出,无论是可执行文件,目标文件,汇编文件还是 预处理后的C代码.

这里只是给出了gcc最常见的指令,如果还想了解更多的细节可以查看下官方文档.这里给出国内维护的GCC中文手册

如上的GCC相关指令给出了一整套处理C语言文件的完整方法,下面使用来完整的按流程编译下C语言文件。

预处理阶段(preprocessing)

再看一眼test.c文件

使用gcc -E filename > outputFilename预处理文件

gcc -E test.c

将信息输出到test.i文件之中

原本只有二十五行的代码,一下子被扩张到了751行

基本数据类型的重新定义

标准输入输出函数

外部函数

test.c代码段

这里说的代码段不准确,代码段是整个代码,这里是特指test.c中手动写入的代码区

预处理后效果分析

  • 插入了头文件信息
  • 宏消失,发生了宏替换
  • 注释删除

编译阶段(compilation)

使用gcc -S filename

gcc -S test.i

编译生成了test.s文件,只是一个汇编代码文件

借助汇编代码翻译为机器码

汇编代码

讨论汇编代码已经超过了本次讨论的内容,这里附上一篇讲解汇编的文章汇编代码,里面正对于计算机内存,与CPU的关系阐释的相当清楚,各位有时间可以看看。

可以从汇编代码的一些细节处看出来,这汇编代码实际上是原test.c向汇编语言的翻译,像C语言这样计算机编程语言实际上是高级语言,简单来说是给人看的,语法等等各个方面的都适用于人类去阅读,但是计算机是无法理解的。计算机只能理解0和1,二进制, (最开始电子计算机刚刚被发明出来的时候,程序员们编程就是使用的手动输入01二进制指令的方法编程的),带有特定功能的二进制码被称为指令,指令的集合被称为指令集,(这也正是当前中国被卡脖子的地方)汇编语言是机器码的封装,每一个汇编指令都对应与一个机器码,这也是为什么汇编语言被成为低级语言。

梳理下编译阶段

我们不去考察GCC是如何巴拉巴拉变出这一堆看不懂的汇编代码,但我们应当明白,C语言是想把自己转化成为汇编码然后直接交给CPU,我们可以这么理解C语言是汇编语言的重构封装,使得,而编译器就好像是翻译器。大致理解为如下流程。

汇编阶段(assembly)

gcc -c filename

gcc -c test.s

汇编阶段是汇编语言向机器码转化的过程,可以理解为汇编语言的编译过程。

强行读取一下

虽然基本上是乱码,但是其中还是有不少的部分如I know PI equels to %lf等等字符串类型的数据可以被显示出来。但是此程序还无法交给CPU计算,还缺少最后一步连接(link)

连接阶段(link)

gcc filename -o targetname

    -o选项实际上可以处理很多种类的中间文件,如果没有使用`-o'选项,默认的输出结果是:可执行文件为`a.out', `source.suffix '的目标文件是`source.o',汇编文件是 `source.s',而预处理后的C源代码送往标准输出.
gcc test.o -o test

最终的阶段终于得到了真正的目标文件,完成了一次人机的简单交互。

但是这个gcc -o实际上给出的很暧昧,这个过程中实际上是把我们自己写好的程序与存储在硬盘的库文件连接,比如说printf()函数,并没有定义它,但是却可以使用,这是由于上述操作与标准库建立了连接.

!!!注意!!!,所有的可执行程序必须放在CPU中才可以运行!!****

举个例子也许会好理解一些:

​ 你们全家人要出去郊游,你跟妈妈说我要吃大雪糕,妈妈答应给你准备。

​ 你把你的想法传达给了妈妈,你们一起建立起了一个约定,可以理解为上述汇编阶段产生的未连接的可执行文件

​ 妈妈答应了你的约定,可是,如何去履现和你的承诺呢?

  1. 在郊游地点周围现买.(假设郊游地点周围一定有)

  2. 在家里就准备好,打包一起带走到郊游地点.

    这导出了两种不同的连接方式:

    1. 静态连接:一起打包好,我要的我都准备好。(对应于上述的在家里准备雪糕)
    2. 动态链接: 我暂时不准备,但是我知道,它雪糕就在那儿,所以等到了之后在动态的把它拿过来执行。

很容易想到动态链接的文件体积会相对来说少很多,但是可移植性差点。

反思

真正的可执行的程序在经过预处理,编译,汇编,连接相关库文件。最终形成了程序的最终形态,当次文件执行的时候,立马从硬盘读取到了内存中,然后立马放置到CPU进行计算。

如何避免代码段出现内存错误呢?

​ 代码段,是存放指令集的,所以我列举出了以下几个方面可能造成的错误.

  		1. 阻止C文件翻译为汇编代码
2. 阻止库连接,或者库连接失败

阻止C文件翻译为汇编代码:

#include <stdio.h>

int mian() {
printf("Mushroon!!!!\n");
return 0;
}

如上代码,故意将函数入口main写成mian``int写成intt

虽然我们已经尽力的想去迫害C语言的编译器,可是它还是认真的指出了我们的恶劣行经。

预处理完全没问题,编译阶段出现了问题,失败了,超出了C语言编译器可以理解的符号系统

阻止库连接

回到上面给出的一家人郊游你却想吃雪糕的例子,当你提出吃雪糕的时候,你妈妈给你一大耳巴子,说"吃什么吃!不给吃!!",这就是阻止了库的连接。自然无法完成你想要吃雪糕这件事了。

总结

实际上本文没有得到什么比较深刻的结论。

目前随着编译器越来越完善,各大IDE(集成式编程环境)越来越强大,语义分析,自动查询语法错误,还能在不编译的时候察觉出想C语言编译器无法查出的问题:如数组访问越界。

这些工具的出现使得编程时代码准确无误的被翻译成为机器码,确保可以执行,让程序员更注重于程序的功能上,是否准确?是否有效?这也是时代的一大进步吧!

引用

C语言编译过程

GNU计划手册

汇编语言入门教程

C语言代码区错误以及编译过程的更多相关文章

  1. C/C++编译过程

    C/C++编译过程 C/C++编译过程主要分为4个过程 1) 编译预处理 2) 编译.优化阶段 3) 汇编过程 4) 链接程序 一.编译预处理 (1)宏定义指令,如#define Name Token ...

  2. C编译过程概述

    转自:http://my.oschina.net/apeng/blog/105245 C 编译过程概述 目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection), ...

  3. [转贴]C编译过程概述

    http://my.oschina.net/apeng/blog/105245 C 编译过程概述 目前Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是G ...

  4. C语言编译过程

    GCC编译C源码有四个步骤: 预处理-----> 编译 ----> 汇编 ----> 链接 一. 编译和链接的流程 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在 ...

  5. .NET 代码编译过程

    作为一种代码指令平台,Microsoft .NET比微软公司先前推出的其他技术平台要来得更为复杂.由于.NET提供了对多种编程语言以及(在理论上说)多重平台的支持,这就需要在传统的两个代 码层添加一个 ...

  6. 我学C的那些年[ch01]:浅淡C语言的编译过程

    前几天大致学习了C语言的编译过程,那么今天就和大家分享一下 首先,编译C语言,需要一个文本编辑器(windows自带的也行),和一个MinGW编译器(需要配置环境),就可以将.c文件编译成.exe文件 ...

  7. C语言编译过程简介

    刚开始接触编程的时候,只知道照书敲敲代码,一直都不知道为什么在windows平台下代码经过鼠标那样点击几下,程序的结果就会在那个黑色的屏幕上.现在找了个机会将C语言的编译原理做一下小小的总结,这样也能 ...

  8. C语言笔记——简介与编译过程初探

    序言 从今天起,详细说说C语言.这一年多,在大多数语言和技术之间转了一大圈,终于看清楚了事实,决心静下心来好好学学C语言.初学者会认为C语言是个入门用的东西,没有必要深入研究.但对计算机领域再稍加了解 ...

  9. c语言的编译过程和GCC 编译参数

    原文: http://www.cnblogs.com/zhangShanGui/p/4912135.html C语言的编译过程和GCC编译参数 C语言的编译一般有三个步骤: 预编译: gcc -E - ...

随机推荐

  1. Linux中数据库的安装和配置(MySQL与Maria DB)

    目录 MySQL和Maria DB的介绍 MySQL和Maria DB的安装 yum源安装MySQL(Centos6.5+Mysql5.1) 源码包安装MySQL yum源安装Maria DB 源码包 ...

  2. DVWA之File Upload (文件上传漏洞)

    目录 Low: Medium: 方法一:抓包修改文件的type 方法二:00截断 High: Impossible : Low: 源代码: <?php if( isset( $_POST[ 'U ...

  3. hdu5246超级赛亚ACMer

    题意(中文题意直接粘吧)                             超级赛亚ACMer Problem Description   百小度是一个ACMer,也是一个超级赛亚人,每个ACM ...

  4. OGG-Oracle同步Sequence

    一.需求,使用OGG同步软件,将Oracle 11g Sequence实时同步到19c新库中 参考文档 Implementing replication of cyclic sequences in ...

  5. MySQL 8.0配置文件my.ini文件位置

    文件位置 C:\ProgramData\MySQL\MySQL Server 8.0 如果看不到ProgramData文件夹,可能是被隐藏了.打开显示隐藏文件夹选项即可

  6. mysql注入getshell

    0x00 利用条件 root权限 secure_file_priv=为空或者在网站根目录下(网站根目录为d:\www,secure_file_priv=d:\也可以) 知道绝对路径 gpc关闭,这个应 ...

  7. [刷题] 209 Minimum Size Subarray Sum

    要求 给定一个含有 n 个正整数的数组和一个正整数 s 找出该数组中满足其和 ≥ s 的长度最小的连续子数组 如果不存在符合条件的连续子数组,返回 0 示例 输入:s = 7, nums = [2,3 ...

  8. [Windows] 屏幕截图 - FastStone Capture(FSCapture) v9.4 飞扬时空汉化绿色版(官方地址) 【清晰好用 已验证】

    [Windows] 屏幕截图 - FastStone Capture(FSCapture) v9.4 飞扬时空汉化绿色版(官方地址) [复制链接]     愤怒の葡萄 电梯直达 楼主    发表于 2 ...

  9. 055.Python前端Django模型ORM

    由于前面在centos实验的过程中,pymql一直有属性错误,很难排查出问题,重新做了一个ubuntu的桌面系统同时使用pycharm开发工具作为学习开发工具,具体原因是因为在项目命名出现问题,和自己 ...

  10. Spark SQL 之 RDD、DataFrame 和 Dataset 如何选择

    引言 Apache Spark 2.2 以及以上版本提供的三种 API - RDD.DataFrame 和 Dataset,它们都可以实现很多相同的数据处理,它们之间的性能差异如何,在什么情况下该选用 ...