头歌——Linux——下的 c 编程

简介: 头歌——Linux——下的 c 编程

可以先看几个 shell 编程找找感觉 , 哈哈

#!/bin/bash
sum=0
f1=0
f2=1
#-e 开启echo的转义功能,尾部加\c表示不换行
echo -e "$f1+$f2\c"
#使用expr执行加法
sum=`expr $sum + $f1 + $f2`
#shell脚本中的for循环
for i in $(seq 3 10)
      do
        f3=`expr $f1 + $f2`
        sum=`expr $sum + $f3`
        f1=$f2
        f2=$f3
        echo -e "+$f3\c"
      done
echo -e "=$sum"
#!/bin/bash
reverseNum(){
    array_len=$# #测试集个数
    for num in $*
    do
        #请在此处键入您的代码
        x=$num
        #ans=""
        while [ $x -gt 0 ]
        do
            t=$[$x%10]
            echo -e "$t\c"
            #ans=$[$ans$t]
            x=$[$x/10]
        done
        echo ""
    done
}
 #!/bin/bash
 #请在此处键入你的代码
 # 创建 userdata 目录
 if [ -d /home/userdata ]
 then
    chmod 754 /home/userdata
 else
    mkdir -m 754 /home/userdata
fi
 i=1
 temp=/home/userdata/user
 while [ $i -le 5 ]
 do
    if [ -d $temp$i ]
    then
        chmod 754 $temp$i
    else
        mkdir -m 754 $temp$i
    fi
    i=$[$i+1]
 done
#!/bin/bash
read -p "Please input an integer number: " number
echo -e "the result of '\c"
sum=0
for((i=1;i<=number;i++))
do
    sum=$[$i+sum]
    if [ $i -le 3 ]
    then
        echo -e "$i+\c"
    elif [ $i -eq $number ]
    then
        echo -e "...$i\c'"
    fi
done
echo -e "' is ==> $sum"
[root@hadoop100 ~]$ vim test.c
#include <stido.h>
int mian()
{
  printf("Hello world");
  return 0;
}
[root@hadoop ~]$ gcc test.c  
// `gcc`默认使用`a.out`作为可执行文件的名字;
[root@hadoop ~]$ ./a.out // ./a.out表示运行当前目录下的a.out命令;


c 语言从程序源代码到二进制执行程序需要经历如下四个步骤:

  • 预处理
  • 预处理是根据处理指令组装新的 C / C ++ 程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有新的不同。
  • 编译
  • 编译是指将预处理完的文件进行行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。
  • 汇编
  • 编译是指将处理完的汇编代码文件翻译成机器指令,并生成重定位目标程序的 .o 文件,该文件为二进制文件,字节码是机器指令。
  • 连接
  • 连接过程是指连接机器一个个目标文件(或许还会有库文件)连接在一起生成完整的可执行程序,这个可执行程序才是我们最后直接执行的文件。


gcc 编译器使用的方法

gcc 命令选项 参数


常用命令选择项如下:

1)-o:指定生成的输出文件名字;
2)-E:仅执行编译预处理;
3)-S:将 C 代码转换成汇编代码
4)-c:仅执行编译和汇编操作,不进行连接操作
5)-I:包含库所在的路径
6)-L:指定库所在的路径
7)-l:指定使用的库(小写)
[root@hadoop ~]$ vim firstExec.c
#include <stdio.h>
int main()
{
  printf("Hwllo GCC\n");
  return 0;
}
[root@hadoop ~]$ gcc -S first.c
[root@hadoop100 ~]$ ls -l first.s
[root@hadoop100 ~]$ tail firstExec.s
[root@hadoop100 ~]$ gcc firstExec.c -o firstExec


第3关:Linux 之静态库编写


1)相关知识

在实际的软件开发时, 应该遵守一个基本原则:不要重复造轮子。如果某些代码经常要用到,不仅这个项目能使用,而且也能复用到其它项目上,那么就应该把这部分代码从项目中分离出来,将其编译为库文件,供需要的程序调用。


程序库分为两类,分别是静态库动态库。本关将主要讲解如何生成静态库


Windows系统上的静态库是以.lib为后缀,而Linux系统上的静态库是以.a为后缀的特殊的存档。


Linux系统的标准系统库可在目录 /usr/lib/lib 中找到。比如,在类 Unix 系统中C语言的数序库一般存储为文件 / usr/lib/libm.a 。该库中函数的原型声明在头文件 /usr/include/math.h 中。


生成静态库

Linux 下,我们可以使用 gccar 工具制作和使用自己的静态库,具体过程如下:

1. 将源码文件编译成 .o 目标文件;
2. 使用 ar 工具将多个目标打包成 .a 的静态文件;


注意 Linux 系统上默认的静态库名格式为: libxxx.a,其中 xxx 为生成库的名称。

案例演示1:

编写一个函数 printHello ,其功能为打印 “Hello world" 字符串,将其编译生成名为 Hello 的静态库,可以使用如下命令:

vim printHello.h
vim printHello.c
gcc -c printHello.c -o printHello.o
ar rcs libHello.a printHello.o


  • 使用 vim 编写 printHello.h (声明 printHello函数,方便以后被其它程序调用)
#ifndef __PRINTHELLO_H__
#define __PRINTHELLO_H__
#include <stdio.h>
void printHello();
#endif


  • 使用 vim 编写printHello.c
#include <stdio.h>
void printHello()
{
printf("Hello world\n");
}


使用静态库

静态库的使用方法只需要在编译程序的时候指明要链接的库名称即可,gcc 中有两个参数是关于链接库时所使用的,分别是:-L-l

  1. -L:用于告诉gcc要链接的库所在目录;
  2. -l:用于指明链接的库名称(小写l);


案例演示1:

调用以上案例生成的 printHello 函数,可以使用如下命令:

vim main.c
gcc main.c -o exe -L
./ -lHello./exe


  • 使用vim编写main.
#include "printHello.h"
int main()
{
printHello();
return 0;
}


样例代码

  1. vim printHello.h

#ifndef __PRINTHELLO_H__
#define __PRINTHELLO_H__
#include <stdio.h>
void printHello();
#endif


  1. vim printHello.c

#include <stdio.h>
void printHello()
{
    printf("Hello world\n");
}


  1. gcc -c printHello.c -o printHello.o
  2. ar rcs libHello.a printHello.o
  3. vim main.c

#include "printHello.h"
int main()
{
    printHello();
    return 0;
}


  1. gcc main.c -o exe -L ./ -lHello
  2. ./exe


编程要求

本关任务是学会生成和使用静态库。

具体编程要求如下:

  • 在当前目录下编写一个简单的函数int Add(int a, int b),其功能为计算输入参数a+b的结果;
  • 将Add函数编译生成一个静态库libAdd.a,并存放在当前目录下;


测试说明

本关的测试需要用户在右侧的命令行下完成,用户只需将需要完成的命令在右侧命令行下直接操作即可,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。


  1. vim Add.h
#include <stdio.h>
int Add(int a, int b);


  1. vim Add.c
#include <stdio.h>
int Add(int a, int b)
{
    printf("%d\n", a + b);
}


  1. gcc -c Add.c -o Add.o
  2. ar rcs libAdd.a Add.o
  3. vim main.c
#include "Add.h"
int main()
{
    Add(1, 2);
    return 0;
}
  1. gcc main.c -o out -L ./ -lAdd
  2. ./out


第4关:Linux之动态库编写

任务描述

本关任务:学会在Linux系统上生成C语言的动态库。


相关知识

上一关学习了如何生成静态库,本关将继续讲解如何生成动态库

  • 静态库动态库的区别:


静态库 动态库
名称 命名方式是"libxxx.a",库名前加"lib",后缀用".a","xxx"为静态库名 命名方式是"libxxx.so", 库名前加"lib",后缀用".so", "xxx"为动态库名
链接时间 静态库的代码是在编译过程中被载入程序中 动态库在编译的时候并没有被编译进目标代码,而是当你的程序执行到相关函数时才调用该函数库里的相应函数
优点 在编译后的执行程序不在需要外部的函数库支持,因为所使用的函数都已经被编进去了。 动态库的改变并不影响你的程序,所以动态函数库升级比较方便
缺点 如果所使用的静态库发生更新改变,你的程序必须重新编译 因为函数库并没有整合进程序,所以程序的运行环境必须提供相应的库

Windows系统上的 动态库 是以.dll为后缀,而Linux系统上的 动态库 是以 .so 为后缀的特殊的存档。


生成动态库

Linux下,我们可以使用 gcc 制作和使用动态库,具体制作过程如下:

使用gcc命令加-fPIC参数将源码文件编译成.o目标文件;
使用gcc命令加-shared参数将多个目录文件生成一个动态库文件;

注意Linux 系统上默认的动态库名格式为:libxxx.so,其中xxx为生成库的名称。


案例演示1:

编写一个函数printHello,其功能为打印"Hello world"字符串,将其编译生成名为Hello的动态库,可以使用如下命令

vim printHello.h
vim printHello.c
gcc -fPIC -c printHello.c -o printHello.o
gcc -shared printHello.o -o libHello.so


  • 使用vim编写printHello.h(申明printHello函数,方便以后被其它程序调用)
#ifndef __PRINTHELLO_H__
#define __PRINTHELLO_H__
#include <stdio.h>
void printHello();
#endif


  • 使用vim编写printHello.c
#include <stdio.h>
void printHello()
{
printf("Hello world\n");
}


使用动态库

动态库的使用方法与静态库使用方式略有不同,除了使用gcc中的-L-l参数外,想要调用动态库还需要更新Linux系统中/etc/ld.so.cache或者修改LD_LIBRARY_PATH环境变量,否则在运行程序的时候会报**“No such file or directory”**错误。

案例演示1:

调用以上案例生成的printHello函数,可以使用如下命令:

vim main.c
gcc main.c -o exe -L ./ -lHello
./exe


更新/etc/ld.so.cache来运行动态库
  • 编辑/etc/ld.so.conf配置文件,然后加入需要加载的动态库目录。
  • 运行ldconfig更新/etc/ld.so.cache


案例演示1:

更新/etc/ld.so.cache,然后运行上一个案例生成的exe,可以使用如下命令:

sudo vim /etc/ld.so.conf
sudo ldconfig
./exe


修改LD_LIBRARY_PATH环境变量

在运行可执行文件前修改LD_LIBRARY_PATH变量为可执行程序指定需要加载的动态库路径。

案例演示1:

修改LD_LIBRARY_PATH,然后运行上一个案例生成的exe,可以使用如下命令:

LD_LIBRARY_PATH=. ./exe


注意

  1. LD_LIBRARY_PATH告诉了exe程序现在当前目录下寻找链接的动态库;
  2. 当运行环境中同时存在同名的静态库和动态库时,默认优先链接动态库;
  3. vim printHello.h
#ifndef __PRINTHELLO_H__
#define __PRINTHELLO_H__
#include <stdio.h>
void printHello();
#endif


  1. vim printHello.c
#include <stdio.h>
{
  printf("Hello world\n");
}


  1. gcc -fPIC -c printHello.c -o printHello.o
  2. gcc -shared printHello.o -o libHello.so
  3. ls -l libHello.so
[root@hadoop102 样例演示]# ls -l libHello.so
-rwxr-xr-x. 1 root root 8120 Sep  3 15:16 libHello.so


  1. vim main.c
// 在这里调用的库必须是用双引号好引起来
#include "printHello.h"
int main()
{
    printHello();
    return 0;
}


  1. gcc main.c -o exe -L ./ -lHello
  2. sudo vim /etc/ld.so.conf
  3. ldconfig
  4. LD_LIBRARY_PATH=. ./exe
  5. ./exe


编程要求

本关任务是学会生成和使用动态库。

具体编程要求如下:

  • 在当前目录下编写一个简单的函数int Sub(int a, int b),其功能为计算输入参数a-b的结果;
  • 将Sub函数编译生成一个动态库libSub.so,并存放在当前目录下;
  • 修改/etc/ld.so.conf,添加当前目录,并更新/etc/ld.so.cache


测试说明

本关的测试需要用户在右侧的命令行下完成,用户只需将需要完成的命令在右侧命令行下直接操作即可,然


  1. vim Sub.h
#ifndef __PRINTHELLO_H__
#define __PRINTHELLO_H__
#include <stdio.h>
int Sub(int a, int b);
#endif


  1. vim Sub.c
#include <stdio.h>
int Sub(int a, int b)
{
  return a - b;
}


  1. gcc -fPIC -c Sub.c -o Sub.o
  2. gcc -shared Sub.o -o libSub.so
  3. vim main.c
#include "Sub.h"
int main()
{
    printf("%d\n", Sub(2, 1));
    return 0;
}
  1. vim /etc/ld.so.conf
  2. ldconfig
  3. gcc main.c -o exe -L ./ -lSub
  4. LD_LIBRARY_PATH=. ./exe
  5. ./exe






目录
相关文章
|
3月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
1月前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
3月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
137 6
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
155 3
|
3月前
|
Shell Linux Python
python执行linux系统命令的几种方法(python3经典编程案例)
文章介绍了多种使用Python执行Linux系统命令的方法,包括使用os模块的不同函数以及subprocess模块来调用shell命令并处理其输出。
58 0
|
4月前
|
项目管理 敏捷开发 开发框架
敏捷与瀑布的对决:解析Xamarin项目管理中如何运用敏捷方法提升开发效率并应对市场变化
【8月更文挑战第31天】在数字化时代,项目管理对软件开发至关重要,尤其是在跨平台框架 Xamarin 中。本文《Xamarin 项目管理:敏捷方法的应用》通过对比传统瀑布方法与敏捷方法,揭示敏捷在 Xamarin 项目中的优势。瀑布方法按线性顺序推进,适用于需求固定的小型项目;而敏捷方法如 Scrum 则强调迭代和增量开发,更适合需求多变、竞争激烈的环境。通过详细分析两种方法在 Xamarin 项目中的实际应用,本文展示了敏捷方法如何提高灵活性、适应性和开发效率,使其成为 Xamarin 项目成功的利器。
53 1
|
4月前
|
安全 Linux 开发工具
探索Linux操作系统:从命令行到脚本编程
【8月更文挑战第31天】在这篇文章中,我们将一起潜入Linux操作系统的海洋,从最基础的命令行操作开始,逐步深入到编写实用的脚本。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和实用技能。我们将通过实际代码示例,展示如何在日常工作中利用Linux的强大功能来简化任务和提高效率。准备好了吗?让我们一起开启这段旅程,探索Linux的奥秘吧!
|
4月前
|
Linux
揭秘Linux心脏:那些让你的编程事半功倍的主要系统调用
【8月更文挑战第31天】Linux中的系统调用是操作系统提供给应用程序的接口,用于请求内核服务,如文件操作、进程控制等。本文列举了22种主要系统调用,包括fork()、exec()、exit()、wait()、open()、close()、read()、write()等,并通过示例代码展示了如何使用fork()创建新进程及使用open()、write()、close()操作文件。这些系统调用是Linux中最基本的接口,帮助应用程序与内核交互。
64 1
|
4月前
|
Linux 程序员 开发者
源社区的兴起:从“代码隐士”到Linux引领的“全球编程嘉年华”
在编程的古老森林中,曾有“代码隐士”默默耕耘,惧怕智慧外泄。直到“开源”春风拂过,源社区如全球编程嘉年华盛开!开源文化颠覆了“独门秘籍”的传统,像“武林秘籍共享”般在网络上公开,鼓励知识传播与智慧碰撞。程序员组队开发,分享代码,提升科技实力。Linux则从“首席大厨”变身为“总导演”,以强大内核调制出诱人应用,引领潮流并推动技术创新。加入这场没有血腥厮杀,只有知识盛宴的“编程版《饥饿游戏》”吧!与全球开发者共享编程的乐趣与成就感!别忘了带上你的“独门秘籍”,可能下一个改变世界的创意就在其中!
70 7