avatar

Linux下C语言的快速入手

首先,我们有如下输出hello,world!程序:

  • hello.c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
    #if 1
    //argument count
    //argument value
    int main(int argc, char **argv)
    {
    printf("hello, world!\n");
    return 5;
    }
    #endif

    一、基本操作

    程序代码与Windows平台的程序并无不同,只是在不同的环境中具有不同的约定。
    在Linux环境下,不以文件拓展名作为区分文件的标准。
  • 编译:
1
root@aemonair:~/tmp# gcc hello.c -o hello
  • 运行:
1
2
root@aemonair:~/tmp# ./hello 
hello, world!

编译的具体步骤:

Ⅰ.预处理

  • 生成.i的文件:
1
root@aemonair:~/tmp# gcc -E hello.c -o hello.i
1
root@aemonair:~/tmp# vim hello.i

使用 vim 或者任意编辑器打开hello.i可以看到是将头文件展开去掉注释等操作的预处理之后的文件。


Ⅱ.编译

  • 将预处理后的文件转换成汇编语言,生成文件.s:
1
root@aemonair:~/tmp# gcc -S hello.i -o hello.s

打开hello.s可以看到,是输出hello,worl!的汇编代码。


Ⅲ.汇编

  • 将汇编代码变为目标代码(机器代码)生成.o的文件
1
root@aemonair:~/tmp# gcc -c hello.s -o hello.o

这时用file命令查看hello.o则发现:

1
2
root@aemonair:~/tmp# file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

此时hello.o是一个二进制64位的可重定位的目标文件。

Ⅳ .链接

1
root@aemonair:~/tmp# gcc hello.o -o hello

生成可执行文件。


二、查看基本信息

  • 查看当前的文件:

    1
    2
    3
    4
    5
    6
    root@aemonair:~/tmp# ls -l  hello*
    -rwxr-xr-x 1 root root 6728 May 27 14:40 hello
    -rw-r--r-- 1 root root 148 May 27 13:25 hello.c
    -rw-r--r-- 1 root root 17187 May 27 13:26 hello.i
    -rw-r--r-- 1 root root 1504 May 27 13:30 hello.o
    -rw-r--r-- 1 root root 497 May 27 13:28 hello.s
  • file命令,

    得以辨识该文件的类型。

1
2
3
4
5
6
7
8
9
10
root@aemonair:~/tmp# file hello.c
hello.c: C source, ASCII text # C语言ASCII码源文件
root@aemonair:~/tmp# file hello.i
hello.i: C source, ASCII text
root@aemonair:~/tmp# file hello.s
hello.s: assembler source, ASCII text # ASCII码汇编文件
root@aemonair:~/tmp# file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped # 二进制64位的可重定位的目标文件
root@aemonair:~/tmp# file hello
hello: 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]=1420b36f9837a8d7ba2f4a9ec6b968d16c403d23, not stripped #可执行的二进制文件
  • objdump

    objdump命令是Linux下的反汇编目标文件或者可执行文件的命令

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
root@aemonair:~/tmp# objdump -s -d hello.o

hello.o: file format elf64-x86-64

Contents of section .text:
0000 554889e5 4883ec10 897dfc48 8975f0bf UH..H....}.H.u..
0010 00000000 e8000000 00b80500 0000c9c3 ................
Contents of section .rodata:
0000 68656c6c 6f2c2077 6f726c64 2100 hello, world!.
Contents of section .comment:
0000 00474343 3a202844 65626961 6e20352e .GCC: (Debian 5.
0010 332e312d 38292035 2e332e31 20323031 3.1-8) 5.3.1 201
0020 36303230 3500 60205.
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 01781001 .........zR..x..
0010 1b0c0708 90010000 1c000000 1c000000 ................
0020 00000000 20000000 00410e10 8602430d .... ....A....C.
0030 065b0c07 08000000 .[......

Disassembly of section .text:

0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 89 7d fc mov %edi,-0x4(%rbp)
b: 48 89 75 f0 mov %rsi,-0x10(%rbp)
f: bf 00 00 00 00 mov $0x0,%edi
14: e8 00 00 00 00 callq 19 <main+0x19>
19: b8 05 00 00 00 mov $0x5,%eax
1e: c9 leaveq
1f: c3 retq

-s 除了显示test的全部Header信息,还显示他们对应的十六进制文件代码
-d 反汇编test中的需要执行指令的那些section

  • readelf命令

    readelf用来显示ELF格式目标文件的信息.可通过参数选项来控制显示哪些特定信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@aemonair:~/tmp# readelf -s -d hello.o

Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS hello.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 5
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 8
8: 0000000000000000 0 SECTION LOCAL DEFAULT 6
9: 0000000000000000 32 FUNC GLOBAL DEFAULT 1 main
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND puts

三、基本基础

  • 返回值
  • 若要在Bash中获得函数运行的返回值,则在终端中输入以下代码并回车。
    1
    echo $?
1
2
root@aemonair:~/tmp# echo $?
5

一般的正确返回则返回0;这里的5是我们为了查看效果。
若我们再执行一次echo $?则会是多少呢?

1
2
root@aemonair:~/tmp# echo $?
0

因为我们这时的返回值是成功执行了echo的成功返回值,故为0。

  • main函数参数:
    int argc :参数的个数
    char **argv : 参数的值 //也可写成char *argv[];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*argtest.c*/
#include <stdio.h>
//argument count
//argument value
int main(int argc, char **argv)
{
int i = 0 ;
printf("argc: %d\n",argc);
for(i = 0; i < argc ;++i)
{
printf("argv[%d]:%s\n",i,argv[i]);
}
return 0;
}

编译源文件为可执行文件:

1
root@aemonair:~/tmp# gcc argtest.c -o argtest

./argtest.c 1 2 c def $ 运行得到:

1
2
3
4
5
6
7
8
root@aemonair:~/tmp# ./argtest 1 2 c def $ 
argc: 6
argv[0]:./argtest
argv[1]:1
argv[2]:2
argv[3]:c
argv[4]:def
argv[5]:$

可见,argc是命令行传入的参数个数,argv是一个二位指针,可以通过[ ]将其值%s打印出来。
而且,argv[0]即是程序名本身。

  • 条件编译:
  • 此时,codes2的内容将不会运行。
    1
    2
    3
    4
    5
    #if 1
    //codes
    #else
    //cods 2
    #endif
    可用来作为注释或程序运行时的条件决策。

总结:此文只是简单的对LinuxC语言的开发快速入手进行简单介绍。

文章作者: Air
文章链接: http://aemonair.github.io/2016/05/31/Linux_C_Quick_Start/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Aemonair