头歌——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






目录
相关文章
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
11月前
|
安全 算法 Ubuntu
Linux(openssl)环境:编程控制让证书自签的技巧。
总结:在Linux环境中,OpenSSL是一个非常实用的工具,可以帮助我们轻松地生成自签名证书。通过上述三个简单步骤,即可为内部网络、测试环境或开发环境创建自签名证书。但在公共访问场景下,建议购买经过权威认证机构签发的证书,以避免安全警告。
546 13
|
JavaScript Ubuntu Linux
如何在阿里云的linux上搭建Node.js编程环境?
本指南介绍如何在阿里云Linux服务器(Ubuntu/CentOS)上搭建Node.js环境,包含两种安装方式:包管理器快速安装和NVM多版本管理。同时覆盖全局npm工具配置、应用部署示例(如Express服务)、PM2持久化运行、阿里云安全组设置及外部访问验证等步骤,助你完成开发与生产环境的搭建。
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
275 26
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
299 17
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
703 13
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
960 6
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
542 3
下一篇
开通oss服务