首先,我们有如下输出hello,world!
程序:
hello.c1 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!
编译的具体步骤: Ⅰ.预处理
1 root@aemonair:~/tmp# gcc -E hello.c -o hello.i
1 root@aemonair:~/tmp# vim hello.i
使用 vim
或者任意编辑器打开hello.i
可以看到是将头文件展开去掉注释等操作的预处理之后的文件。
Ⅱ.编译
1 root@aemonair:~/tmp# gcc -S hello.i -o hello.s
打开hello.s可以看到,是输出hello,worl!
的汇编代码。
Ⅲ.汇编
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 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的内容将不会运行。
可用来作为注释或程序运行时的条件决策。
总结:此文只是简单的对Linux 下C语言 的开发快速入手进行简单介绍。