Linux程序设计

前言

简单总结了Shell脚本设计,C in Linux 的编程和编译,以及GTK+的简单原理

Shell程序设计

bash程序执行步骤

  1. 编辑保存vi
  2. 赋可执行权限chmod
  3. ./filename.sh执行

bash程序结构

# file.sh

1
2
3
4
5
6
7
8
9
#!/bin/bash		****Shell类型****

# 注释
# 函数定义
function funn() {

}

.... # 主过程

变量

定义变量

1
变量=值	# "="两边不能留空格

变量都会被默认成字符串

引用变量

用户自定义变量要加$,加{}可以同其他字符分开(建议添加)

1
${xxx}

双引号

会替换$变量成值。参数中包含空格也要用双引号。

单引号

字符串值,不会替换$变量

倒引号 ``

替换命令为其执行结果

特定变量

1
2
3
4
5
6
7
8
$@		# 参数列表(数组)
$* # 参数列表(字符串)
$# # 参数个数
$n # 位置参数$1,$2,$3...$n
$0 # 本脚本文件名
$$ # 本程序进程号
$? # 上一条命令或函数的返回值
$HOME # 用户主目录

算术运算

expr 命令

计算算术表达式,支持 +-\*/%要``\``进行转移,否则会错误)

支持|&>>=!==等逻辑运算,|,>,<要用\转义才能使用

语法:

1
expr arg

数字符 和 符号 间要空格

要改变运算次序的话需要使用``倒引号

`expr 5 \* 7` + 5```
1
2
3
4
5
6
7
8
9

---

### let 命令

**语法**:给a赋值(语法中**不用空格**!)

```bash
let a=(5+7)/3

$((…))运算

直接运算得出结果

示例:

1
echo $((5+7))

条件判断

0真,1假(与熟知C语言判断相反)

语法:注意!中括号两边要空格!!!

1
[ 条件判断语句 ]

多重条件判断组合

1
2
3
-a	# 与
-o # 或
! # 非

算术比较:

1
2
3
4
5
6
7
a -eq b		# 相等(equal)
a -ne b # 不相等(not equal)
a -gt b # a大于b(greater then)
a -ge b # a大于等于b(greater equal)
a -lt b # a小于b(less then)
a -le b # a小于或等于b(less equal)
!expr # 假则真,真则假

字符比较:

1
2
3
4
s1 = s2		# 字符串相同
s1 != s2 # 字符串不同
-n str1 # 字符串不为空
-z str1 # 字符串为空

文件判断

1
2
3
-d file		# 是目录
-e file # 存在
-f file # 是文件

if 分支语句

结构:

1
2
3
4
5
6
7
8
if [ 条件1 ]
then
命令
elif [ 条件2 ]; then
命令
else
命令
fi

case 模式匹配 分支语句

结构:

1
2
3
4
5
6
7
case 条件1 in
模式n)
命令n
;;
*) #default
命令
esac

模式匹配配对符:

1
2
3
4
5
?		# 任意一个字符
* # 任意字符串
[] # 括号中的任意字符
[!] # 不在括号中的任意字符
{c1,c2} # 和c1或者c2匹配都可

for 循环

结构:

1
2
3
4
for 变量 [in 列表]
do
命令
done

可用 in 1,2,3,4...或者默认使用in $@。其中$@是参数数组

while 循环

结构:

1
2
3
4
while/until [ 条件 ]
do
命令
done

函数

结构:

1
2
3
4
[function] 函数名(){
命令
[return xx]
}
  • 如果最后不使用return返回,函数返回的就是最后一条命令的返回值

C in Linux

gcc编译过程

gcc编译过程

gcc命令

语法:

1
gcc [选项] [filename]

选项:

1
2
3
4
5
6
7
8
-c			# 编译.c文件生成.o文件,不生成可执行文件
-o filename # 指定生成文件名称为filename。不设这个选项则默认为filename.xx(根据编译阶段生成后缀文件)
-Idir # 在编译时增加搜索头文件的目录
-Ldir # 在编译时增加搜索库的目录
-lname # 在编译时装在名为libname.a的函数库,需要存在于系统预设目录或-L设置的目录。
-g # 加入调试信息
-E # 生成.i预处理文件
-S # 生成.s汇编文件

总结:在编译过程中。除非使用了”-c”,“-S”,或”-E”选项(或者编译错误阻止了完整的过程),否则统一完整链接步骤。

编译

分步编译

先用-c,-S,-E中断编译过程,生成中间文件,再用gcc 中间文件完成编译

示例:

1
2
3
gcc -c hello.c -o hello.o
gcc -c say_hello.c -o say_hello.o
gcc hello.o say_hello.o -o hello

一步编译

1
gcc hello.c say_hello.c -o hello

使用-Idirname增加搜索头文件目录

示例:

当前目录为./hello.c ./functions/say_hello.h ./functions/say_hello.c

1
gcc hello.c functions/say_hello.c -o hello -Ifunctions

make 软件维护工具

makefile文件

格式:

1
2
3
目标文件: 依赖项列表
命令
...

依赖项可以不写.h文件,但一定要写清.c文件的路径

示例:

当前目录为./hello.c ./functions/say_hello.h ./functions/say_hello.c

1
2
3
4
5
6
hello:hello.o say_hello.o
gcc hello.o say_hello.o -o hello
hello.o:hello.c say_hello.h
gcc -c hello.c -o hello.o -Ifunctions
say_hello.o:functions/say_hello.c
gcc -c functions/say_hello.c -o say_hello.o -Ifunctions

makefile可以使用变量宏命令${}

1
2
3
CC=-Wall-c
hello:${CC}
.......

使用makefile

在存放makefile文件的目录下使用:make

调试工具 gdb

  1. 设置断点
  2. 监视变量
  3. 单步执行
  4. 修改变量值

进入gdb:gdb

使用gdb

1
2
3
file		# 装入可执行文件
list # 查看源代码
quit # 退出gdb
1
2
3
4
5
6
7
8
9
10
# 执行程序
break <line> # 设置断点
next # 单步执行
step # 单步执行到函数内部
run # 执行程序
kill # 终止正在调试的程序

# 监视变量
watch # 监视变量
print # 打印变量

函数库

静态函数库

库文件名libxxxxx.a

静态函数库文件比较大,因为整个函数库的所有代码都会被整合编译到目标代码中,所以使用静态库编译后的程序不需要外部函数库支持,因为都已经编译进去了。但是如果今天函数库改变了就需要重新编译。

创建

编译生成.o文件:gcc -c pr1.c pr2.c

链接静态库:ar -rsv libpr.a pr1.o pr2.o

使用

加载库文件编译:gcc -o main main.c -L./ -lpr

动态函数库

库文件名:libxxxx.so

动态函数库在编译时没有被编译进目标代码中,当程序执行到时才会调用函数里的相应函数。所以使用动态函数库产生的可执行文件较小。

创建

生成动态库:gcc -fpic -shared -o libpr.so pr1.c pr2.c

使用

调用动态库:gcc -o main_so main.c ./libpr.so

GTK+

GTK+控件

GtkWidget:GTK控件的父类,所有控件按照此类型返回

创建控件:GtkWidget * gtk_xxxx_new(GtkNodeType type 或者 void)

设置xxx:void gtk_xxx_set_xxx(GtkNode *xxx, XX message)

读取xxx:xx gtk_xxx_get_xxx(GtkNode *xxx)

存放进窗体:gtk_container_add(GTK_CONTAINER(windowxx), xxxx)

显示窗体:gtk_widget_show_all(window)

界面布局采用横向hbox和纵向vbox

示例:

1
2
3
4
5
6
7
8
9
10
11
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window, *button; //声明window和button为GtkWidget,后面使用需要类型转换
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); // 初始化window变量为GTK....类型
gtk_window_set_title(GTK_WINDOW(window), "HELLO WORLD"); //这里用的大写是类型转换
button = gtk_button_new_with_label("Hello World"); // 初始化button变量为button类型
gtk_container_add(GTK_CONTAINER(window), button) //类型转换成Container,button放入window
gtk_widget_show_all(window);
gtk_main();
return;
}

回调函数、信号

GTK+用信号(signal)和回调函数(callback)处理外部事件。

信号与回调函数绑定

采用g_signal_connect函数来完成信号和回调函数绑定。

1
2
3
4
g_signal_connect(gpointer *object,	// 连接信号的对象
const gchar *name, // 信号名
Gcallback func, // 回调函数名
gpointer user_data) // 回调函数参数的指针

回调函数

回调函数的函数原型(用户自己定义):

1
2
void callback_func(GtkWidget *widget,	// 发出信号的控件的指针
gpointer callback_data)// 传递进函数的数据