其实我也不知道是为了啥, 到了现在这种年纪还想学习Linux下的C语言编程。因为我一直就傻傻地认为机会是垂青有准备的人,也一直呆呆地认为活到老学到老。现在Android这么火,各种终端如雨后春笋,而这些终端如果不安装Windows的,势必会使用开源的Linux,而Linux上面跑的程序,C还是占据很大市场的,一旦时机成熟,就可以立马换车改门庭,不至于产生职业耽误。这就是我的这种蠢蠢的初衷。在深圳,特别是现在这个时段,周围的人想到的是如何快速的融入股市,杀进房金融市场,趁着牛市的尾巴赚个盆满钵满,买房买车,迎娶白富美,实现人生的伟大理想。我这种想法似乎十分幼稚,但此时此刻,当我发布这篇随笔时,我的的确确就是这么想的。

回到今天的主题,我今天是想先通过一个简单的Hello,World的程序,然后讲讲Module,讲讲Makefile 等一些非常初级的c编程,如果你很熟悉Linux和C的话,那么你可以选择绕过这篇,或者你可以在后面发表你的建议,欢迎批评指正,但拒绝一上来就乱喷的青子,我们都过了那个年龄了。

首先来看一下我使用的gcc版本

cc -v

或者

gcc -v

至于为什么两个命令得到的是相同的信息gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)呢? 这是因为cc是unix下的编译器,而现在大多数的linux上,都把cc连接到gcc。也就是说cc是gcc的软连接。

1,  开始我们的第一个程序代码编写吧,这里我使用的编辑器是vim

vim hello.c

然后在hello.c里输入

#include <stdio.h>int main(int argc, char* argv[])
{prinftf("Hello,World!");    return 0;
}

:wq!出来之后,继续输入

gcc hello.c -o hello.out && ./hello.out

就这么简单,就可以得到我们伟大的Hello, World程序了。

这里我只是补充说明一下上面如果不使用-o hello.out来指定输出的文件名的话,那么gcc会默认生成一个叫a.out的文件出来。那么后面的连接的就应该相应的改成a.out了,也就是

gcc hello.c && ./a.out

当然,如果你觉得这个&& 突兀的冒出来,一时不知是干什么用的话,那么你也可以分成两批去执行,先编译,然后再执行。其实&&的作用就是将两个命令合在一起提交,如果前一个命令如果没有返回错误的话,那么继续执行下一条命令。上面的语句就是编译完hello.c没有错误的话,紧接着就执行刚编译出来的程序。对于我来说,我是喜欢用&&来联接的,我在网上下载下来的源程序也常喜欢make && make install来一步执行。因为我觉得./configure 没有错的话,后面基本上没有啥大问题了,当然这不是绝对。

2, 伟大的Hello,World就完成了。之所以伟大,就是因为其极其简单,武侠小说里面常常也说简单就是实用,比如杨过练的独孤九剑,使用的剑是要比平常人的宝剑要重得的多的,谓之曰重剑不锋。但是一直靠大砍大杀的简单招式去对敌的话,估计也成就不了神雕大侠的。所以还有独孤九式,还有黯然销魂掌等等,所以接下来,我们也来把hello.c改变一点点,注意是一点点,仍然很简单,就是我们让hello.c里的main方法去调用另一个方法。

#include <stdio.h>int main(int argc, char* argv[])
{int a=33;int b=22;int maxNo=max(a,b);printf("the max number is %d",maxNo);  return 0;
}int max(int a, int b)
{if(a>b) return a;return b;
}

嗯,上面这段代码最终输出:

the max number is 33.

按照我们的意愿得到了结果,这是一个很好的开端。但是我们想想,如果这个max函数是由别人来协同开发的,两个人不可能都来修改hello.c这个文件吧?如果是那样的话就乱套了,merge 的时候都会把人搞疯的。为了不疯人,为了少抓狂,我们把max这个函数另存进一个max.c文件里去,或者由另一位同事去实现。

这里我讲一下我的操作是这样子的。

vim hello.c

打开编辑,然后再把光标移到int max(int a,intb)的那一行,按5dd得到5行到剪贴板,然后:sp max.c,然后ctrol+w+上光标键,最后按p,将复制的那5行码贴入max.c里,最后:wqa!

分开了两个文件之后,我们的编译就得这样了:

gcc max.c hello.c -o hello.out

最后执行

./hello.out

也可以得到想要的正确结果。

the max number is 33.

3, 嗯,很好,完成了分离了,结果如预期所想。完美解决方案。可是不久之后,又有人实现了一个min.c的模块,并且通知了hello.c去调用一下并显示出最小的数据出来。于是编译相应的就改成了

gcc max.c min.c hello.c -o hello.out

没错,就是将相关的.c文件列举上去就可以,很容易很简单,可是如果项目一旦复杂,.c文件有上千个,那岂不要累死程序员,累死那个发布的同事了吗?当然不可以,我们对于每个人都是不抛弃不放弃。所以我们使用Makefile来解救他们。

#this is a make file for hello.out
hello.out:max.c min.c hello.c gcc max.c min.c hello.c -o hello.out

那么接下在bash里面直接输入make就可以了。当然,作为第一次使用,我还是没有忘记使用make -v看一下我使用的版本号是多少:

最后执行的结果也是想要的预期结果。

4, 似乎很完美了,可是我们去看看Makefile的内容,总有一种异样的怪怪感。当然如果没有发现也很正常,毕竟我们还只有三个文件,而且现在的机器也是很快的,执行make时也不会有啥差异的。其实如果我们去看网上下载的Makefile 之后,发现很多不怎么变的文件,都会有.o的形式存在的。另外源代码里面可能还充斥着很多.h的文件。那么这些文件是干什么的。为什么会存在这类文件呢?在回答这类问题之前,首先我要申明,不是非要以.o, .h来命名,只不过约定俗成罢了,.o就是模块文件,也就是不常变动的.c 文件可以先编译成.o作为模块保存下来。 .h文件是给调用者说明的,他一般只包含.c文件的方法的签名即可。说得更接近高级语言一点,就是相当于c#(java)里的interface.

接下来,我就把max.c转成max.o, 将min.c转成min.o保存下来。并且生成两份.h文件出来,最后也提供一份更接近生产的Makefile,注意这个M是要大写的,这也是约定,而且这个约定是不能变的。

gcc -c max.c
gcc -c min.c

然后max.h和min.h文件输入的内容是:

int max(int a, int b);

int min(int a ,int b);

最后的Makefile

#this is a make file for hello.out
hello.out:max.o min.o hello.c gcc max.o min.o hello.c -o hello.out
max.o:max.cgcc -c max.c
min.o:min.cgcc -c min.c

5,  最后,我把我的代码全部贴上来吧。

int max(int a, int b)
{if(a>b) return a;return b;
}

max.c

int max(int a, int b)
{if(a<b) return a;return b;
}

min.c

#include <stdio.h>
#include "max.h"
#include "min.h"int main(int argc, char* argv[])
{int a=33;int b=22;int maxNo=max(a,b);int minNo=min(a,b);printf("the max number is %d"\nthe min number is %d\n",maxNo,minNo);  return 0;
}

hello.c

6,  关于我的第一个linux的C程序就是这样子的,Happy ending, right?

7,  不,这样的结局并不完美。作为一个程序员,我并没有觉得很happy,因为上面并没有讲到如何调试。都是一次过的简单程序,能够一次性将所有程序逻辑(包括复杂的)写出来就真是大牛逼人物了。 静态的编译错误还好说,make阶段就能发现,可是有些逻辑却不是那么容易发现的。程序员的终极武器debug就要祭出了。在linux里面一般用的就是gdb工具。按照惯例看一下我的版本先:

为了调试我上面的那个小程序,我将所有的*.o文件和hello.out先删除掉。

rm -rf *.o
rm -rf hello.out

然后修改Makefile成如下:

#this is a make file for hello.out
hello.out:max.o min.o hello.c gcc -g max.o min.o hello.c -o hello.out
max.o:max.cgcc -g -c max.c
min.o:min.cgcc -g -c min.c

执行make之后。继续输入

gdb ./hello.out

这样就加载了我们hello.out进了内存,而且可以调试了。至于什么是栈内存、堆内存、数据内存,代码内存这些,我就不说了,可以回去翻翻大学教程或者网络上自己搜索一下吧,贴出我的一些简单的调试操作吧:

8, 最后解决一个小问题,就是在上面的图中,我们可以看到其中出现了一个错误说Missing separate debuginfos, use: debuginfo-install glibc-2.17-78.el7.x86_64

其实要解决这个问题,也很简单,直接在bash下面输入

debuginfo-install glibc

前提是我已有/etc/yum.repos.d/CentOS-Debug.repo如下:

# CentOS-Debug.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
## All debug packages from all the various CentOS-7 releases
# are merged into a single repo, split by BaseArch
#
# Note: packages in the debuginfo repo are currently not signed
#[base-debuginfo]
name=CentOS-7 - Debuginfo
baseurl=http://debuginfo.centos.org/7/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-Debug-7
enabled=0
#

CentOS-Debug.repo

如果没有就需要先到http://debuginfo.centos.org/7/x86_64/ 找到与内核完全一样的debuginfo. 例如机器的内核是CentOS Linux 7 (Core) Kenerl 3.10.0-229.el7.x86_64 on an x86_64,  就是在输入用户名的登录时可以看到这个信息。 那么就应该

wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-3.10.0-229.el7.x86_64.rpm
wget http://debuginfo.centos.org/7/x86_64/kernel-debuginfo-common-x86_64-3.10.0-229.el7.x86_64.rpm

然后rpm安装下载到的rpm包,不过我认为可能不需要下载这两个应该也是可行的。最后仿照配置yum源并执行

debuginfo-install glibc

就可以解决这个问题。

9, 至于如何使用gdb,网上找到两篇介绍文章

http://www.cnblogs.com/hankers/archive/2012/12/07/2806836.html

http://blog.csdn.net/feixiaoxing/article/details/7199643

转载于:https://www.cnblogs.com/SLKnate/p/linux_centos7_helloworld_with_c.html

CentOS 7 之Helloworld with c相关推荐

  1. centos 安装低版本内核_Docker安装教程

    Docker的应用场景 Web 应用的自动化打包和发布.自动化测试和持续集成.发布.在服务型环境中部署和调整数据库或其他的后台应用.从头编译或者扩展现有的 OpenShift 或 Cloud Foun ...

  2. 尚硅谷docker基础篇 2018版

    typora-root-url: ./image Docker基础篇之快速上手 第一章 Docker简介 是什么? 问题:为什么会有 docker 的出现 一款产品从开发到上线,从操作系统,到运行环境 ...

  3. docker镜像操作

    docker镜像操作 实验环境 操作系统:CentOS Linux release 7.3.1611 (Core)docker版本:17.11.0-ce 镜像操作 列出镜像 查看已经下载下来的镜像: ...

  4. docekrfile

    1.Dockerfile常用指令 1.FROM 语法:FROM : 指明构建的新镜像来自那个基础镜像,如果没有选择tag,那么默认值为latest. FROM centos:7 #如果不以任何镜像为基 ...

  5. 360云 Ubuntu安装Dokcer

     360云Ubuntu安装Dokcer cat /etc/issue Ubuntu 14.04.2 LTS \n \l 内核版本 uname -r 3.16.0-30-generic 相比阿里云, ...

  6. docker pull拉取镜像原理_Dockerfile镜像细节

    原文:https://blog.csdn.net/weixin_31244053/article/details/112206093 docker pull nginx:1.13 # 观察下面拉取进度 ...

  7. Java程序设计(Java9版):第1章 Java开发环境配置 (Set up Java development environment)

    第1章Java开发环境配置(Set up Java development environment) 工欲善其事,必先利其器. - <论语·卫灵公> Write once, run any ...

  8. Docker 个人记录

    文章目录 一.前言 1. 基本概念 一.搭建 二.启动 .停止 三.镜像操作 四.容器操作 五.网络模式 六.容器设置固定ip 七.镜像制作 八.容器可视化 shipyard的安装使用 一.前言 目前 ...

  9. CentOS Docker安装配置部署Golang web helloworld

    目录[阅读时间:约5分钟] 一.Docker简介 二.Docker的安装与配置[CentOS环境] 三.Docker部署Golang web helloworld 四.Docker与虚拟机的区别 五. ...

  10. GO语言教程(一)Linux( Centos)下Go的安装, 以及HelloWorld

    写在前面: 目前,Go语言已经发布了1.5的版本,已经有不少Go语言相关的书籍和教程了,但是看了一些后,觉得还是应该自己写一套Go语言的教程.给广大学习Go语言的朋友多一种选择.因为,咱写的教程,向来 ...

最新文章

  1. centos7下安装docker(14安装docker machine​)
  2. Spring事务的处理流程、传播属性、及部分释疑
  3. 随便唠叨下 最近的事情
  4. Android开发在路上:少去踩坑,多走捷径
  5. Html5带来了什么?
  6. zepto部分报错及解决方案
  7. NOD32病毒库自动更新代码
  8. 街道设计导则与城市道路系统的优化提升:从通行能力到空间品质的转变
  9. vba字典的key属性、item属性和keys方法、items方法、add方法
  10. nginx的网页压缩以及图片的压缩
  11. 趣图:你永远想不到用户怎么使用你的产品
  12. pg_partman
  13. 华尔街英语宝典,架构师必备技能
  14. vimdiff比较两个文件
  15. CSS学习笔记(内边距~文字在盒子里的垂直居中)
  16. 【亲测】独家更新CcPay多商户码支付系统,码支付易支付+个人支付宝微信二维码收款app监控+搭建教程
  17. 基于机智云物联网平台的实验室智能安防报警系统
  18. cad2014打开出现显示驱动程序缺少或损坏
  19. 服务器中调试微信支付免预充,微信支付-统一支付接口被坑经历
  20. 【CCF-CSP】202112-3 登机牌条码

热门文章

  1. Github删除历史提交记录的方法
  2. 安装GNOME3桌面并设置开机启动图形界面
  3. 字节序Endian与字节序标记BOM详解
  4. C++:构造函数中调用虚函数
  5. Could not locate call adapter for io.reactivex.Observable
  6. CF1149BThree Religions
  7. 执行董事和非执行董事的区别
  8. 解决火狐浏览器中文乱码问题
  9. 关于瀚高数据库的适配
  10. 201771010112罗松《面向对象程序设计(java)》第一周学习总结