Linux学习-使用传统程序语言进行编译的简单范例
单一程序:印出 HelloWorld
- 编辑程序代码,亦即原始码
[root@study ~]# vim hello.c <==用 C 语言写的程序扩展名建议用 .c
#include <stdio.h>
int main(void)
{
printf("Hello World\n");
}
在预设的状态下,如果我们直接以 gcc 编译原始码,并且没有加上任何参数,则执行档的档名会被 自动设定为 a.out 这个文件名!所以妳就能够直接执行 ./a.out 这个执行档啦!那如果我想要产生目标文件 (object file) 来进行其他的动作,而且执行档的档名也不要用 预设的 a.out ,那该如何是好?其实妳可以将上面的第 2 个步骤改成这样:
[root@study ~]# gcc -c hello.c
[root@study ~]# ll hello*
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o <==就是被产生的目标文件
[root@study ~]# gcc -o hello hello.o
[root@study ~]# ll hello*
-rwxr-xr-x. 1 root root 8503 Sep 4 11:35 hello <==這就是可執行檔! -o 的結果
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o
[root@study ~]# ./hello
Hello World
这个步骤主要是利用 hello.o 这个目标文件制作出一个名为 hello 的执行文件,
主、子程序链接:子程序的编译
如果我们在一个主程序里面又呼叫了另一个子程序呢?这是很常见的一个程序写法, 因为可以简化整个程序的易读性!在底下的例子当中,我们以 thanks.c 这个主程序去呼叫 thanks_2.c 这个子程序,写法很简单:
- 撰写所需要的主、子程序
# 1. 编辑主程序:
[root@study ~]# vim thanks.c
#include <stdio.h>
int main(void)
{
printf("Hello World\n");
thanks_2();
}
# 上面的 thanks_2(); 那一行就是呼叫子程序啦!
[root@study ~]# vim thanks_2.c
#include <stdio.h>
void thanks_2(void)
{
printf("Thank you!\n");
}
- 进行程序的编译与链接 (Link)
# 2. 开始将原始码编译成为可执行的 binary file :
[root@study ~]# gcc -c thanks.c thanks_2.c
[root@study ~]# ll thanks*
-rw-r--r--. 1 root root 75 Sep 4 11:43 thanks_2.c
-rw-r--r--. 1 root root 1496 Sep 4 11:43 thanks_2.o <==编译产生的!
-rw-r--r--. 1 root root 91 Sep 4 11:42 thanks.c
-rw-r--r--. 1 root root 1560 Sep 4 11:43 thanks.o <==编译产生的!
[root@study ~]# gcc -o thanks thanks.o thanks_2.o
[root@study ~]# ll thanks*
-rwxr-xr-x. 1 root root 8572 Sep 4 11:44 thanks <==最终结果会产生这玩意儿
# 3. 执行一下这个文件:
[root@study ~]# ./thanks
Hello World
Thank you!
知道为什么要制作出目标文件了吗?由于我们的原始码文件有时并非仅只有一个文件,所以我们无法 直接进行编译。这个时候就需要先产生目标文件,然后再以连结制作成为 binary 可执行文件。另外, 如果有一天,你更新了 thanks_2.c 这个文件的内容,则你只要重新编译 thanks_2.c 来产生新的 thanks_2.o ,然后再以连结制作出新的 binary 可执行文件即可!而不必重新编译其他没有更动过的 原始码文件。
此外,如果你想要让程序在执行的时候具有比较好的效能,或者是其他的除错功能时, 可以在编译 的过程里面加入适当的参数,例如底下的例子:
[root@study ~]# gcc -O -c thanks.c thanks_2.c <== -O 为产生优化的参数
[root@study ~]# gcc -Wall -c thanks.c thanks_2.c
thanks.c: In function ‘main’:
thanks.c:5:9: warning: implicit declaration of function ‘thanks_2’ [-Wimplicit-function-declaration]
thanks_2();
^
thanks.c:6:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
# -Wall 为产生更详细的编译过程信息。上面的讯息为警告讯息 (warning) 所以不用理会也没有关系!
呼叫外部函式库:加入连结的函式库
刚刚我们都仅只是在屏幕上面印出一些字眼而已,如果说要计算数学公式呢?例如我们想要计算出三 角函数里面的 sin (90 度角)。要注意的是,大多数的程序语言都是使用径度而不是一般我们在计算的 『角度』, 180 度角约等于 3.14 径度!嗯!那我们就来写一下这个程序吧!
[root@study ~]# vim sin.c
#include <stdio.h>
#include <math.h>
int main(void)
{
float value;
value = sin ( 3.14 / 2 );
printf("%f\n",value);
}
那要如何编译这支程序呢?我们先直接编译看看:
[root@study ~]# gcc sin.c
# 新的 GCC 会主动将函数抓进来给你用,所以只要加上 include <math.h> 就好了!
新版的 GCC 会主动帮你将所需要的函式库抓进来编译,所以不会出现怪异的错误讯息! 事实上, 数学函式库使用的是 libm.so 这个函式库,你最好在编译的时候将这个函式库纳进去比较好~另外要 注意, 这个函式库放置的地方是系统默认会去找的 /lib, /lib64 ,所以你无须使用底下的 -L 去加入 搜寻的目录! 而 libm.so 在编译的写法上,使用的是 -lm
- 编译时加入额外函式库连结的方式:
[root@study ~]# gcc sin.c -lm -L/lib -L/lib64 <==重点在 -lm
[root@study ~]# ./a.out <==尝试执行新文件!
1.000000
特别注意,使用 gcc 编译时所加入的那个 -lm 是有意义的,他可以拆开成两部份来看:
- -l :是『加入某个函式库(library)』的意思,
- m :则是 libm.so 这个函式库,其中, lib 与扩展名(.a 或 .so)不需要写
所以 -lm 表示使用 libm.so (或 libm.a) 这个函式库的意思~至于那个 -L 后面接的路径呢?这表示: 『我要的函式库 libm.so 请到 /lib 或 /lib64 里面搜寻!』
除了连结的函式库之外,你或许已经发现一个奇怪的地方,那就是在我们的 sin.c 当中第一行『 #include <stdio.h>』,这行说的是要将一些定义数据由 stdio.h 这个文件读入,这包括 printf 的相关设定。这个文件其实是放置在 /usr/include/stdio.h 的!那么万一这个文件并非放置在这里呢?那 么我们就可以使用底下的方式来定义出要读取的 include 文件放置的目录:
[root@study ~]# gcc sin.c -lm -I/usr/include
-I/path 后面接的路径( Path )就是设定要去搜寻相关的 include 文件的目录。不过,同样的,默认值 是放置在 /usr/include 底下,除非你的 include 文件放置在其他路径。
gcc 的简易用法 (编译、参数与链结)
底下我们就列举 几个 gcc 常见的参数,如此一来大家应该更容易了解原始码的各项功能吧!
# 仅将原始码编译成为目标文件,并不制作链接等功能:
[root@study ~]# gcc -c hello.c
# 会自动的产生 hello.o 这个文件,但是并不会产生 binary 执行档。
# 在编译的时候,依据作业环境给予优化执行速度
[root@study ~]# gcc -O hello.c -c
# 会自动的产生 hello.o 这个文件,并且进行优化喔!
# 在进行 binary file 制作时,将连结的函式库与相关的路径填入
[root@study ~]# gcc sin.c -lm -L/lib -I/usr/include
# 这个指令较常下达在最终连结成 binary file 的时候,
# -lm 指的是 libm.so 或 libm.a 这个函式库文件;
# -L 后面接的路径是刚刚上面那个函式库的搜寻目录;
# -I 后面接的是原始码内的 include 文件之所在目录。
# 将编译的结果输出成某个特定档名
[root@study ~]# gcc -o hello hello.c
# -o 后面接的是要输出的 binary file 檔名
# 在编译的时候,输出较多的讯息说明
[root@study ~]# gcc -o hello hello.o -Wall
# 加入 -Wall 之后,程序的编译会变的较为严谨一点,所以警告讯息也会显示出来!
Linux学习-使用传统程序语言进行编译的简单范例的更多相关文章
- Linux学习笔记—vim程序编辑器
vi和vim vim是vi的升级版,支持vi的所有指令 vi的使用 vi分为三种模式:一般模式.编辑模式.命令行模式 一般模式 以vi打开一个文件就直接进入一般模式了,这个模式下可以使用上下左右按键来 ...
- [Linux]方便openmp等程序的类似编译
因为总是打参数例如-fopenmp或者-lGL等等有些麻烦,所以特地写一个可以使用的bash文件用来执行简单的操作 首先在.profile中添加 if [ -d "$HOME/bin&quo ...
- Linux环境下用C语言实现socket 通信---简单代码
Socket编程实例: 服务器端:一直监听本机的8000号端口,如果收到连接请求,将接收请求并接收客户端发来的消息,并向客户端返回消息. 客户端:client.c /* File Name: clie ...
- Linux学习总结(十八)几个简单的文本处理工具cut sort tr split
1 命令cut 用来截取某一个字段格式 : cut -d '分隔符' [-cf] n, n为数字,表示第几段-d:后面跟分隔符,分割符要加单引号-c:后面接的是第几个字符-f:后面接的是第几段那么意思 ...
- linux学习书籍推荐《鸟哥的Linux私房菜》下载
下载地址:点我 <鸟哥的Linux私房菜:基础学习篇>是具有知名度的Linux入门书<鸟哥的Linux私房菜基础学习篇>的最新版,全面而详细地介绍了Linux操作系统.< ...
- 简单易懂的程序语言入门小册子(1):基于文本替换的解释器,lambda演算
最近比较闲,打算整理一下之前学习的关于程序语言的知识.主要的内容其实就是一边设计程序语言一边写解释器实现它.这些知识基本上来自Programming Languages and Lambda Calc ...
- linux应用程序设计--GCC程序编译
GCC程序编译 linux系统下的GCC(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一.GCC可以在多种硬件平台上编译出可执行程序,其执行效率与一 ...
- Linux C 程序 空语句-gcc编译命令(SIX)
C语言语句1.空语句:当一个if或者while判断部分能完成工作,空语句可以用来表示if或者while内的空循环体 if(a == b ); 2.gcc编译器 //程序的编译过程: // 预处理:pr ...
- Linux学习-核心编译的前处理与核心功能选择
硬件环境检视与核心功能要求 根据自己的需求来确定编译的选项 保持干净原始码: make mrproper 我们还得要处理一下核心原始码底下的残留文件才行!假设我们是第一次 编译, 但是我们不清楚到底下 ...
随机推荐
- Java基础:(七)反射
一.什么是反射 理解反射之前,先要搞懂一件事情,类加载到底是怎么一回事? 类加载相当于Class对象的加载.每个类都有一个Class对象,包含了与类有关的信息.当编译一个新类时,会产生一个同名的.cl ...
- 老生常谈Java虚拟机垃圾回收机制(必看篇)
二.垃圾收集 垃圾收集主要是针对堆和方法区进行. 程序计数器.虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收. 判断一 ...
- 洛谷 P1202 [USACO1.1]黑色星期五Friday the Thirteenth
黑色星期五 难度:☆ Code: #include <iostream> #include <cstdio> #include <cstring> using na ...
- java 使用uuid生成唯一字符串
UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.按照开放软件基金会(OSF)制定的标准计算, ...
- SQL必知必会-笔记
一.数据库/数据表 数据库(DATABASE):存储有组织的数据的容器; 数据库管理系统(DBMS):数据库软件.开发者通过 DBMS 操纵 DATABASE 表(TABLE):表是一种结构化的文件, ...
- Android里的网格空隙
在很多移动端或者web端开发中我们会遇到很多网格布局,如果我们使用线性布局来实现一些简单的网格布局就需要使用padding/margin等属性来使其对齐,代码如下: <LinearLayout ...
- PHP的socket通信原理及实现
对TCP/IP.UDP.Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵.那么我想问: 1. 什么是TCP/IP.UDP?2. Sock ...
- sizeof(int)
sizeof()操作符检测的是系统为后面()中的类型.变量等分配的内存空间的字节数,这里()中是int,就是求系统为int类型的变量分配几个字节. 在16位int平台下是2:在32位int平台下是4: ...
- 中国各运营商(电信、联通、移动、铁通)IP地址段
除此电信.联通.移动.铁通之外还有教育网.科技网.广电.长城.广电…… 表格下载: http://files.cnblogs.com/files/xiaohi/中国IP网段.zip 以上资料参考: h ...
- 新萝卜家园GHOST WIN7系统32,64位官方版下载
来自系统妈:http://www.xitongma.com 新萝卜家园GHOST win7系统64位官方经典版 V2016年3月 系统概述 新萝卜家园ghost win7系统64位官方经典版加快“网上 ...