基础知识
源程序编译
使用 gcc 编译程序
int main(int argc, char** argv)
{
printf("Hello Linux\n");
}
要编译这个程序,执行以下命令
gcc -o hello hello.c
gcc 编译器会为我们生成一个可执行文件 hello。
gcc 参数选项
- -o 表示我们要求编译器为我们输出可执行文件。
- -c 表示我们只要求编译起输出目标代码,而不必输出可执行文件。
- -g 表示我们要求编译器在编译的时候提供对程序的调试信息。
MakeFile 的编写
假设我们有以下几个源文件
/*main.c*/
#include "mytool1.h"
#include "mytool2.h"
int main(int argc, char** argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/*mytool1.h*/
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char* print_str);
#endif
/*mytool1,c*/
#include "mytool1.h"
void mytool1_print(char* print_str)
{
printf("This is mytool1 print %s\n", print_str);
}
/*mytool2.h*/
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char* print_str);
#endif
/*mytool2.c*/
#include "mytool2.h"
void mytool2_print(char* print_str)
{
printf("This is mytool2 print %s \n", print_str);
}
如果程序很短可以直接使用命令来编译
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main mian.o mytool1.o mytool2.o
这样也可以生成 main 的执行文件,当文件多的时候需要使用 Makefile 来组织源码的编译。
# Makefile
# target: components
# TAB rule
# 第一行表示依赖关系,第二行是规则
#
main: main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
# gcc -o $@ $^
main.o: main.c mytool1.c mytool2.c
gcc -c main.c
# gcc -c $<
mytool1.o: mytool1.c mytool1.h
gcc -c mytool1.c
# gcc -c $<
mytool2.o: mytool2.c mytool2.h
gcc -c mytool2.c
# gcc -c $<
Makefile 的一般格式:
target: compenents
TAB rule
第一行表示的是依赖关系,第二行是规则。
比如说我们上边的 Makefile
main: main.o mytool1.o mytool2.o
表示我们的目标(target)main 依赖的对象(compenents) 是 mian.o mytool1.o mytool2.o
Makefile 有三个非常有用的变量 $@, $^, $<
- $@: 目标文件
- $^ : 所有的依赖文件
- $< : 第一个依赖文件
简化后的 makefile
# Makefile
# target: components
# TAB rule
# 第一行表示依赖关系,第二行是规则
#
main: main.o mytool1.o mytool2.o
# gcc -o main main.o mytool1.o mytool2.o
gcc -o $@ $^
main.o: main.c mytool1.c mytool2.c
# gcc -c main.c
gcc -c $<
mytool1.o: mytool1.c mytool1.h
# gcc -c mytool1.c
gcc -c $<
mytool2.o: mytool2.c mytool2.h
# gcc -c mytool2.c
# gcc -c $<
一个 Makefile 缺省规则
..c.o:
gcc -c $<
这个规则表示所有的 .o 文件都是依赖与对应的 .c 文件的
程序库的链接
如下文件
#include <math.h>
int main(int argc, char** argv)
{
double value;
printf("Value: %f\n", value);
}
当我们使用 gcc -o temp temp.c 编译是会报错。,在编译时需要链接确定的库,为了使用数学函数,需要加入 -lm 选项。
gcc -o temp temp.c -lm
对于一些常用的函数实现,gcc 编译器会自动选择去链接一些常用库,这样我们就没有必要去指定了。
有时候我们在编译程序的时候还要制定库的路径,这个时候就需要用 -L 选项制定路径,比如我们有一个库在 /home/hoyt/mylib 下,这样我们在编译的时候还要加上 -L/home/hoyt/mylib。
程序的调试
-g 可以生成 gdb 文件。
头文件和系统求助
当我们不清楚一个函数是干什么的时候可以使用 man 去查看详细信息。
man fread
# 输出的文本
FREAD(3) Linux Programmer's Manual FREAD(3)
NAME
fread, fwrite - binary stream input/output
SYNOPSIS
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb,
FILE *stream);
DESCRIPTION
The function fread() reads nmemb items of data, each size bytes long,
from the stream pointed to by stream, storing them at the location
given by ptr.
The function fwrite() writes nmemb items of data, each size bytes long,
to the stream pointed to by stream, obtaining them from the location
given by ptr.
For nonlocking counterparts, see unlocked_stdio(3).
RETURN VALUE
On success, fread() and fwrite() return the number of items read or
written. This number equals the number of bytes transferred only when
size is 1. If an error occurs, or the end of the file is reached, the
return value is a short item count (or zero).
fread() does not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
Manual page fread(3) line 1 (press h for help or q to quit)
...