当前位置:   article > 正文

linux的make和makefile学习_prime.h 库

prime.h 库

准备工作

安装GCC和Make工具

安装中文输入法
参考:http://t.csdn.cn/eH0Ow

sudo apt-get update
sudo apt-get install ibus
sudo apt-get install ibus-pinyin
sudo apt-get install fcitx
sudo apt-get install fcitx-pinyin
  • 1
  • 2
  • 3
  • 4
  • 5

完成后重启
重启进入设置:
在这里插入图片描述

使用GNU链接库

链接到math库

编写复利程序

命名为interest.c

#include <studio.h>
#include <math.h>

int main(void)
{
    int years=15; /*要存多少年 */
    int savings=99000; /*存多少钱*/
    float interest=1.5;  /*年利率为1.5%*/

    printf("The total savings after %d years is %.2f\n", years, savings * pow(1+(interest/100),years));
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

编译链接程序:
编译链接库:-lz -lrt -lm -lc都是什么库
-lz 压缩库(Z)
-lrt 实时库(real time):shm_open系列
-lm 数学库(math)
-lc 标准C库(C lib)
-dl ,是显式加载动态库的动态函数库

gcc interest.c -o interest -lm
./interest   #运行程序
  • 1
  • 2

-o指定编译汇编输出程序名

创建自己的库

1、创建头文件:prime.h
在这里插入图片描述

2、创建库文件:prime.c

int isprime(long int number)
{
    long int j;  /*长整型*/
    int prime=1; 

    /*测试是否这个数能被整除,从2开始*/
    for(j=2;j<number;j++)
    {
        /*用取余操作测试这个数能否被整除*/
        if(number%j==0)
        {
            prime=0; //不是素数
        }
    }

    if(prime==1)
    {
        return 1;//素数
    }
    else{
        return 0;//非素数
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3、编译成目标文件

gcc -Wall -Wextra -pedantic -fPIC -c prime.c
  • 1

在这里插入图片描述
-Wall:开启所有警告(可以理解为warinig all),使用它能够使GCC产生尽可能多的警告信息。(非常推荐使用该选项)GCC给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。
-Wextra是关于打开警告的,这些警告可能比其他选项更有用或更麻烦(因为它们可能警告程序员可以接受的代码)。
-pedantic 是 GCC 编译器的一个编译选项。这个选项会让编译器严格遵守 C++ 标准,并输出标准要求的诊断信息,对于一些可能不符合 C++ 标准的语法或者行为会给出警告或者错误提示。
-fpic 该选项用于生成位置无关代码(PIC),尤其被用于共享库的创建(如果目标机器架构支持的话)。使用该选项编译出的代码在访问所有常量地址时,会通过全局偏移表(GOT)进行计算得到。
-c参数是用来编译源代码文件,生成目标文件(object file)的选项(.o)。

4、将目标文件打包成库

 gcc -shared -Wl,-soname,libprime.so -o libprime.so prime.o
  • 1

使用 -shared 选项生成共享库时,最好还是带上 -fpic 或 -fPIC 等选项。
-Wl后面的东西是作为参数传递给链接器ld的
-soname则指定了动态库的soname(简单共享名,Short for shared object name)
这样做的目的主要是允许系统中多个版本的库文件共存,习惯上在命名库文件的时候通常与soname相同
libxxxx.so.major.minor
其中,xxxx是库的名字,major是主版本号,minor 是次版本号
-o指定输出文件名libprime.so
被包含在共享库中的目标文件prime.o
在这里插入图片描述

链接到主目录

1、写程序is-it-a-prime.c,调用共享库libprime.so

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "prime.h"

int main(int argc, char *argv[])
{
    long int num;

    /*只接收一个参数*/
    if (argc!=2)
    {
        fprintf(stderr, "Usage: %s number\n", argv[0]);//stderr -- 标准错误输出设备
        return 1;
    }

    /*只接收数字0-9*/
    if (strspn(argv[1],"0123456789")!=strlen(argv[1]))
    //strspn返回字符串s开头连续包含字符串accept内的字符数目。 若strspn()返回的数值为n,则代表字符串s 开头连续有n 个字符都是属于字符串accept内的字符。
    // strlen函数:当计算长度时,只有遇到'\0'才会停止计算,同时计算的长度不包含'\0'。
    {
        fprintf(stderr, "Only numeric values are accepted\n");
        return 1;
    }

    num=atol(argv[1]); //atol() C 标准库 - <stdlib.h> 描述 C 库函数 long int atol(const char *str) 把参数 str 所指向的字符串转换为一个长整数(类型为 long int 型)。
    if(isprime(num)) //是否素数
    {
        printf("%ld is a prime\n", num);
    }
    else
    {
        printf("%ld is not a prime\n", num);
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

2、链接

gcc -L${PWD} is-it-a-prime.c -o is-it-a-prime -lprime #指定共享库路径
export LD_LIBRARY_PATH=${PWD}:${LD_LIBRARY_PATH} #设置环境变量为共享库目录(当前目录)
  • 1
  • 2

在这里插入图片描述
-L用来告诉gcc去哪里找库文件。 通常来讲, gcc默认会在程序当前目录、/lib、/usr/lib和/usr/local/lib下找对应的库。
-L /home/hello/lib,表示将/home/hello/lib目录作为第一个寻找库文件的目录, 寻找的顺序是:/home/hello/lib–>/lib–>/usr/lib–>/usr/local/lib
LD_LIBRARY_PATH 这个环境变量是大家最为熟悉的,它告诉loader:在哪些目录中可以找到共享库。可以设置多个搜索目录,这些目录之间用冒号分隔开。
假如现在需要在已有的环境变量上添加新的路径名,则采用如下方式:  LD_LIBRARY_PATH=NEWDIRS:$LD_LIBRARY_PATH.(newdirs是新的路径串)

不同的C标准

C89是1989年发布的,兼容性最好,使用最广泛,实现最完整
C99更新一些
写两个进程,分别用C89和C99编译
1、写c文件no-return.c

#include <stdio.h>

int main(void)
{
    printf("Hello, world\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、用C89编译程序

qq@qq-virtual-machine:~/Desktop$ gcc -std=c89 no-return.c -o no-return #用C89标准编译程序
qq@qq-virtual-machine:~/Desktop$ ./no-return #运行程序
Hello, world
qq@qq-virtual-machine:~/Desktop$ echo $? #检查退出码
13
  • 1
  • 2
  • 3
  • 4
  • 5

开启所有警告,重新编译

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c89 no-return.c -o no-return
no-return.c: In function ‘main’:
no-return.c:6:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^
  • 1
  • 2
  • 3
  • 4
  • 5

3、c99标准编译,开启所有警告

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 no-return.c -o no-return
qq@qq-virtual-machine:~/Desktop$ ./no-return #运行程序
Hello, world
qq@qq-virtual-machine:~/Desktop$ echo $?  #检查退出码
0

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

系统调用write()

1、写一个sys-write.c文件

#include <unistd.h>
int main(void)
{
    write(1,"hello, world\n",13);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

unistd.h为Linux/Unix系统中内置头文件,包含了许多系统服务的函数原型,例如read函数、write函数、getopt函数和getpid函数等。
write和exit是系统级函数,是内核提供给applications的接口,属于系统的一部分,可以直接申请内核服务。
在这里插入图片描述

write系统调用,是把缓存区buf中的前nbytes字节写入到与文件描述符flides有关的文件中,write系统调用返回的是实际写入到文件中的字节数。
一般地,一个程序开始运行时,会自动打开3个文件描述符:
0——–标准输入———-stdin
1——–标准输出———-stdout
2——–标准错误———-stderr

2、编译代码

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 sys-write.c  -o sys-write
qq@qq-virtual-machine:~/Desktop$ ./sys-write #运行程序
hello, world
  • 1
  • 2
  • 3

3、编写相同代码用fputs函数,文件名:write-chars.c

#include <stdio.h>
int main(void)
{
    fputs("hello, world\n",stdout);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 write-chars.c -o write-chars
qq@qq-virtual-machine:~/Desktop$ ./write-chars 
hello, world
  • 1
  • 2
  • 3

4、写一个读取用户和系统信息的程序,文件名:my-sys.c
(*)拼音输入不好用解决方案:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/sysinfo.h>

int main(void)
{
    char cwd[100]={0}; /*现在的路径*/
    struct sysinfo si; /*存系统信息*/

    getcwd(cwd,100); /*获取当前工作目录*/
    sysinfo(&si); /*获取系统信息(Linux*/

    printf("Your user ID is %d\n", getuid()); /*用户ID*/
    printf("Your effective user ID is %d\n", geteuid()); /*您的有效用户ID是*/
    printf("Your current working directory is %s\n", cwd); /*目录*/
    printf("Your machine has %ld megabytes of total RAM\n", si.totalram/1024/1024);
    printf("Your machine has %ld megabytes of free RAM\n", si.totalram/1024/1024);
    printf("Currently, there are %d processes running\n", si.procs);
    printf("This process ID is %d\n", getpid());
    printf("This parent process ID is %d\n", getppid());

    return 0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

unistd.h是unix std的意思,是POSIX标准定义的unix类系统定义符号常量的头文件, 包含了许多UNIX系统服务的函数原型
sys/types.h,中文名称为基本系统数据类型,此头文件还包含适当时应使用的多个基本派生类型,常用于从系统取值。
sys/sysinfo.h获取Linux系统信息。

getcwd(cwd,100)获取当前工作目录,两个参数:cwd表示缓冲区,用于保存路径;100为缓冲区长度。
可以从man 2 intro和man 2 syscalls查看系统调用信息。

5、编译运行程序
在这里插入图片描述
由中文字符引起的错误,修改中文字符即可

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 my-sys.c -o my-sys
qq@qq-virtual-machine:~/Desktop$ ./my-sys 
Your user ID is 1000
Your effective user ID is 1000
Your current working directory is /home/qq/Desktop
Your machine has 1983 megabytes of total RAM
Your machine has 1983 megabytes of free RAM
Currently, there are 576 processes running
This process ID is 3528
This parent process ID is 2818

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

一般系统调用出错返回-1。

获取头文件信息

1、安装头文件手册(ubuntu系统)

qq@qq-virtual-machine:~/Desktop$ sudo apt install manpages-posix-dev
[sudo] password for qq: 
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?

  • 1
  • 2
  • 3
  • 4
  • 5

错误原因:有另一个进程正在使用apt命令或dpkg命令,因此无法获得对dpkg锁的访问权限。
解决:重启电脑(虚拟机)

2、阅读手册

qq@qq-virtual-machine:~$ man 2 sysinfo
qq@qq-virtual-machine:~$ man 2 getpid
qq@qq-virtual-machine:~$ man sys_types.h
qq@qq-virtual-machine:~$ man unistd.h

  • 1
  • 2
  • 3
  • 4
  • 5

功能测试宏

1、编写str-posix.c

#include <string.h>
#include <stdio.h>

int main(void)
{
    char a[]="Hello";
    char *b;
    b=strdup(a);
    printf("b=%s\n",b);
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2、用C99标准编译

gcc -Wall -Wextra -pedantic -std=c99 str-posix.c -o str-posix

  • 1
  • 2

在这里插入图片描述
str-posix.c:8:6: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
b=strdup(a);
str posix.c:8:6:警告:赋值使指针从不带强制转换的整数中生成[-Wint conversion]
b=strdup(a);
原因:strdup不是c99一部分
运行程序:

qq@qq-virtual-machine:~/Desktop$ ./str-posix 
b=Hello

  • 1
  • 2
  • 3

3、加宏定义

#define _XOPEN_SOURCE 700

#include <string.h>
#include <stdio.h>

int main(void)
{
    char a[]="Hello";
    char *b;
    b=strdup(a);
    printf("b=%s\n",b);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

重新编译运行:

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 str-posix.c -o str-posix
qq@qq-virtual-machine:~/Desktop$ ./str-posix 
b=Hello

  • 1
  • 2
  • 3
  • 4

4、不设置C标准和功能宏定义,编译器有默认的设置。
编写文件which-c.c,打印正在使用的c标准和功能测试宏。
在这里插入图片描述
在这里插入图片描述

#include <stdio.h>

int main(void)
{
    #ifdef __STDC_VERSION__ /*如果这个宏定义存在*/
        printf("Standard C verision: %ld\n", __STDC_VERSION__); /*%ld 用来输出输出long整数*/
    #endif

    #ifdef _XOPEN_SOURCE /*如果这个宏定义存在*/
        printf("XOPEN_SOURCE: %d\n", _XOPEN_SOURCE); /*%d 用来输出十进制有符号整数*/
    #endif

    #ifdef _POSIX_C_SOURCE /*如果这个宏定义存在*/
        printf("POSIX_C_SOURCE: %ld\n", _POSIX_C_SOURCE); /*%ld 用来输出输出long整数*/
    #endif

    #ifdef _GUN_SOURCE /*如果这个宏定义存在*/
        printf("GUN_SOURCE: %d\n", _GUN_SOURCE); /*%d 用来输出十进制有符号整数*/
    #endif

    #ifdef _BSD_SOURCE /*如果这个宏定义存在*/
        printf("BSD_SOURCE: %d\n", _BSD_SOURCE); /*%d 用来输出十进制有符号整数*/
    #endif

    #ifdef _DEFAULT_SOURCE /*如果这个宏定义存在*/
        printf("DEFAULT_SOURCE: %d\n", _DEFAULT_SOURCE); /*%d 用来输出十进制有符号整数*/
    #endif

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

编译运行:

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic which-c.c -o which-c
qq@qq-virtual-machine:~/Desktop$ ./which-c 
Standard C verision: 201112
POSIX_C_SOURCE: 200809
DEFAULT_SOURCE: 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

版本设为c99:

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 which-c.c -o which-c
qq@qq-virtual-machine:~/Desktop$ ./which-c 
Standard C verision: 199901

  • 1
  • 2
  • 3
  • 4

设置版本设为c99并且宏为600:

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 -D_XOPEN_SOURCE=600 which-c.c -o which-c
qq@qq-virtual-machine:~/Desktop$ ./which-c 
Standard C verision: 199901
XOPEN_SOURCE: 600
POSIX_C_SOURCE: 200112

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

编译的4个步骤

将源代码编译成可运行的二进制程序分为4个步骤,编译只是其中一个步骤。
以编写一个返回给定数字的4次方的小程序
1、写一个cube-prog.c代码文件

#include "cube.h"
#define NUMBER 4

int main()
{
    return cube(NUMBER);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、写一个cubed-func.c文件,实现cube()函数

int cube(int n)
{
    return n*n*n;
}
  • 1
  • 2
  • 3
  • 4

3、写头文件cube.h

int cube(int n);
  • 1

4、gcc编译并运行

qq@qq-virtual-machine:~/Desktop$ gcc -Wall -Wextra -pedantic -std=c99 cube-prog.c cubed-func.c -o cube
qq@qq-virtual-machine:~/Desktop$ ./cube
qq@qq-virtual-machine:~/Desktop$ echo $?
64

  • 1
  • 2
  • 3
  • 4
  • 5

5、重新编译,一步步编译
先把可执行文件cube删除

qq@qq-virtual-machine:~/Desktop$ rm cube

  • 1
  • 2

5.1 第1步为预处理,预处理会对文件进行修改,将#include文件的内容放进程序中。输出.i文件

qq@qq-virtual-machine:~/Desktop$ gcc -E -P cube-prog.c -o cube-prog.i
qq@qq-virtual-machine:~/Desktop$ gcc -E -P cubed-func.c -o cube-func.i

  • 1
  • 2
  • 3

在正常的情况下,GCC 不会保留预处理阶段的输出文件,也即.i文件。然而,可以利用-E选项保留预处理器的输出文件,以用于诊断代码。-E选项指示 GCC 在预处理完毕之后即可停止。
-P 使预处理器不在预处理文件中包含行标记。

查看.i文件:

qq@qq-virtual-machine:~/Desktop$ cat cube-prog.i
int cube(int n);
int main()
{
    return cube(4);
}
qq@qq-virtual-machine:~/Desktop$ cat cube-func.i 
int cube(int n)
{
    return n*n*n;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5.2 第2步为编译,预处理文件被翻译成汇编语言。不同汇编文件在不同机器架构上不同。输出.s文件

qq@qq-virtual-machine:~/Desktop$ gcc -S cube-prog.i -o cube-prog.s
qq@qq-virtual-machine:~/Desktop$ gcc -S cube-func.i -o cube-func.s

  • 1
  • 2
  • 3

给 gcc 指令添加 -S(注意是大写)选项,即可令 GCC 编译器仅将指定文件加工至编译阶段,并生成对应的汇编代码文件。
默认情况下,编译操作会自行新建一个文件名和指定文件相同、后缀名为 .s 的文件,并将编译的结果保存在该文件中。

查看.s文件:

qq@qq-virtual-machine:~/Desktop$ cat cube-prog.s
	.file	"cube-prog.i"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$4, %edi
	call	cube
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 5.3.1-14ubuntu2) 5.3.1 20160413"
	.section	.note.GNU-stack,"",@progbits

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
qq@qq-virtual-machine:~/Desktop$ cat cube-func.s
	.file	"cube-func.i"
	.text
	.globl	cube
	.type	cube, @function
cube:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	%edi, -4(%rbp)
	movl	-4(%rbp), %eax
	imull	-4(%rbp), %eax
	imull	-4(%rbp), %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	cube, .-cube
	.ident	"GCC: (Ubuntu 5.3.1-14ubuntu2) 5.3.1 20160413"
	.section	.note.GNU-stack,"",@progbits

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

5.3 第3步为汇编,将汇编代码构建为目标文件。目标文件为二进制文件,可以用Notepad++加上HEX-Editer插件查看。输出.o文件

qq@qq-virtual-machine:~/Desktop$ gcc -c cube-prog.s -o cube-prog.o
qq@qq-virtual-machine:~/Desktop$ gcc -c cube-func.s -o cube-func.o

  • 1
  • 2
  • 3

gcc -c 只编译并生成目标文件。

.o文件为二进制文件,可以用file查看他们的信息

qq@qq-virtual-machine:~/Desktop$ file cube-prog.o
cube-prog.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
qq@qq-virtual-machine:~/Desktop$ 
qq@qq-virtual-machine:~/Desktop$ file cube-func.o
cube-func.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
qq@qq-virtual-machine:~/Desktop$ 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

用Notepad++查看:
在这里插入图片描述

5.4 第4步为链接,将所有目标文件合并到一个二进制文件中。可以运行它。

qq@qq-virtual-machine:~/Desktop$ gcc cube-prog.o cube-func.o -o cube

  • 1
  • 2
qq@qq-virtual-machine:~/Desktop$ file cube
cube: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8ad60312bea4df59565e0b49d4fe90acc7ce4c34, not stripped
qq@qq-virtual-machine:~/Desktop$ ./cube 
qq@qq-virtual-machine:~/Desktop$ echo $?
64

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

用Make编译

1、写一个circumference.c文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PI 3.14159

int main(void)
{
    char radius[20]={0};

    while(fgets(radius,sizeof(radius),stdin) != NULL)
    {
        //检查radius是数字
        if(strspn(radius,"0123456789.\n")==strlen(radius))
        {
            printf("%.5f\n",PI*(atof(radius)*2));

        }
        else
        {
            fprintf(stderr,"Found non-numeric value\n");
            return 1;
        }
    }
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2、写一个Makefile文件

CC=gcc
CFLAGS=-Wall -Wextra -pedantic -std=c99
  • 1
  • 2

3、make编译

qq@qq-virtual-machine:~/Desktop$ make circumference
gcc -Wall -Wextra -pedantic -std=c99    circumference.c   -o circumference
qq@qq-virtual-machine:~/Desktop$ ./circumference 
5
31.41590
10
62.83180
15
94.24770
9
56.54862
qq@qq-virtual-machine:~/Desktop$ 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Ctrl+D退出

写简单的Make file

1、Makefile:(Makefile文件要与代码文件在同一目录),缩进必须用tab键

CC=gcc
CFLAGS=-Wall -Wextra -pedantic -std=c99

cube: cube.h cube-prog.c cubed-func.c
	$(CC) $(CFLAGS) -o cube cube-prog.c cubed-func.c
  • 1
  • 2
  • 3
  • 4
  • 5

2、编译运行
运行前需要删除之前生成的可执行文件

qq@qq-virtual-machine:~/Desktop$ make
gcc -Wall -Wextra -pedantic -std=c99 -o cube cube-prog.c cubed-func.c
qq@qq-virtual-machine:~/Desktop$ ./cube
qq@qq-virtual-machine:~/Desktop$ echo $?
64

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

写高级的Makefile

1、写一个area.c文件

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <unistd.h>
#include "area.h"

int main(int argc, char *argv[])
{
    int opt;
    //检查选项数量
    if(argc!=2)
    {
        printHelp(stderr,argv[0]);
        return 1;
    }
    //分析命令选项
    while((opt=getopt(argc,argv,"crth"))!=-1)
    {
        switch(opt)
        {
            case 'c':
                if (circle()==-1)
                {
                    printHelp(stderr,argv[0]);
                    return -1;
                }
                break;
            case 'r':
                if (rectangle()==-1)
                {
                    printHelp(stderr,argv[0]);
                    return -1;
                }
                break;
            case 't':
                if (triangle()==-1)
                {
                    printHelp(stderr,argv[0]);
                    return -1;
                }
                break;
            case 'h':
                printHelp(stderr,argv[0]);
                return -1;
            default:
                printHelp(stderr,argv[0]);
                return -1;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

2、写头文件area.h

void printHelp(FILE *stream, char progname[]);
int circle(void);
int rectangle(void);
int triangle(void);
  • 1
  • 2
  • 3
  • 4

3、写一个help.c文件

#include <stdio.h>

void printHelp(FILE *stream, char progname[])
{
    fprintf(stream, "\nUsage: %s [-c] [-t] [-r] [-h]\n"
    "-c calculates the area of a circle\n"
    "-t calculates the area of a triangle\n"
    "-r calculates the area of a rectangle\n"
    "-h shows this help\n"
    "Example: %s -t\n"
    "Enter the height and width of the triangle: 5 9\n"
    "22.500\n",progname,progname);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4、写一个circle.c计算圆面积

#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <math.h>

int circle(void)
{
    float radius;
    printf("Enter the radius of the circle: ");
    if (scanf("%f",&radius))
    {
        printf("%.3f\n", M_PI*pow(radius,2));
        return 1;
    }
    else
    {
        return -1;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

5、写一个rectangle.c计算矩形面积

#include <stdio.h>

int rectangle(void)
{
    float length, width;
    printf("Enter the length and width of the rectangle: ");
    if (scanf("%f %f",&length, &width))
    {
        printf("%.3f\n", length*width);
        return 1;
    }
    else
    {
        return -1;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

6、写一个triangle.c计算三角形面积

#include <stdio.h>

int triangle(void)
{
    float height, width;
    printf("Enter the height and width of the triangle: ");
    if (scanf("%f %f",&height, &width))
    {
        printf("%.3f\n", height*width/2);
        return 1;
    }
    else
    {
        return -1;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7、Makefile文件

CC=gcc
CFLAGS=-Wall -Wextra -pedantic -std=c99
LIBS=-lm
OBJS=area.o help.o circle.o rectangle.o triangle.o
DEPS=area.h
bindir=/usr/local/bin

area: $(OBJS)
	$(CC) -o area $(OBJS) $(LIBS)

area.o: $(DEPS)

clean:
	rm area $(OBJS)

install: area
	install -g root -o root area $(bindir)/area

uninstall: $(bindir)/area
	rm $(bindir)/area
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

8、编译运行

qq@qq-virtual-machine:~/Desktop/area$ make
gcc -Wall -Wextra -pedantic -std=c99   -c -o area.o area.c
gcc -Wall -Wextra -pedantic -std=c99   -c -o help.o help.c
gcc -Wall -Wextra -pedantic -std=c99   -c -o circle.o circle.c
gcc -Wall -Wextra -pedantic -std=c99   -c -o rectangle.o rectangle.c
gcc -Wall -Wextra -pedantic -std=c99   -c -o triangle.o triangle.c
gcc -o area area.o help.o circle.o rectangle.o triangle.o -lm
qq@qq-virtual-machine:~/Desktop/area$ ./area -c
Enter the radius of the circle: 9
254.469
qq@qq-virtual-machine:~/Desktop/area$ ./area -t
Enter the height and width of the triangle: 9 4
18.000
qq@qq-virtual-machine:~/Desktop/area$ ./area -r
Enter the length and width of the rectangle: 9 4
36.000
qq@qq-virtual-machine:~/Desktop/area$ ./area -r
Enter the length and width of the rectangle: 
6
u
0.000
qq@qq-virtual-machine:~/Desktop/area$ ./area -r
Enter the length and width of the rectangle: ab

Usage: ./area [-c] [-t] [-r] [-h]
-c calculates the area of a circle
-t calculates the area of a triangle
-r calculates the area of a rectangle
-h shows this help
Example: ./area -t
Enter the height and width of the triangle: 5 9
22.500

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

LIBS=-lm被添加到area目标命令末尾,用来链接math共享库。所有目标文件被编译,只有在最后阶段,文件都编译成二进制时,才会添加-lm
OBJS列出了所有目标文件
DEPS列出了依赖的头文件
bindir二进制被安装在系统上的完整路径

area 目标命令
area.o 验证依赖关系

9、安装和卸载
安装到系统中:

qq@qq-virtual-machine:~/Desktop/area$ sudo make install
[sudo] password for qq: 
install -g root -o root area /usr/local/bin/area
qq@qq-virtual-machine:~/Desktop/area$ 

  • 1
  • 2
  • 3
  • 4
  • 5

卸载:

qq@qq-virtual-machine:~/Desktop/area$ sudo make uninstall
rm /usr/local/bin/area

  • 1
  • 2
  • 3

清除:

qq@qq-virtual-machine:~/Desktop/area$ make clean
rm area area.o help.o circle.o rectangle.o triangle.o

  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/640930
推荐阅读
相关标签
  

闽ICP备14008679号