- 浏览: 812849 次
- 性别:
- 来自: 西安
文章分类
- 全部博客 (307)
- struts (8)
- hibernate (3)
- spring (32)
- opensourceproject (12)
- javaScript (9)
- primeton EOS (2)
- journey of heart (10)
- Design pattern (6)
- ejb (17)
- point (37)
- Linux&Unix (22)
- ibatis (10)
- AJAX (6)
- DB (26)
- Protocol (6)
- chart (4)
- web server (11)
- webservice (7)
- integration (3)
- tuxedo (5)
- ext (4)
- android (1)
- c/c++ (12)
- JVM (1)
- paginationFrame (2)
- code (2)
- report (1)
- High-performance web (1)
- svn (1)
- JQuery (1)
- workDaily (2)
- cloud (16)
- Python (8)
- English (2)
- shell (5)
- googleCode (1)
- nio (1)
- hyper-v (1)
- debug (3)
- vbs (2)
- openstack (3)
- K8S (1)
- Mesos (0)
- Spark (0)
- Marathon (0)
最新评论
-
钱图大展:
chao2751021 写道lib包哪里去下载,找不到
大型网站用户行为记录的一个实现--基于clickStream(第一部分) -
钱图大展:
无法下载
大型网站用户行为记录的一个实现--基于clickStream(第一部分) -
fm395728572:
shell脚本中用到了环境变量,但是获取不到,例如脚本中有一句 ...
ganymed-ssh2 for Java -
liuhanjiang:
我qq147229234
大型网站用户行为记录的一个实现--基于clickStream(第一部分) -
liuhanjiang:
博主 我利用您提供的方法实现博文中介绍的clickstream ...
大型网站用户行为记录的一个实现--基于clickStream(第一部分)
1.编译过程简述:
1.1 预编译
1.1.1 宏定义指令
#define #undef
1.1.2 条件编译指令
例子: debug , debug.c 内容如下
#include <stdio.h> main() { #ifdef DEBUG fprintf(stderr,"debug infomation \n"); #endif }
在测试环境上 我们使用下面的命令编译:
cc debug.c -DDEBUG -o debug
他的执行结果:
[root@xhu-vm 5]# ./debug
debug infomation
[root@xhu-vm 5]#
我们看到了debug 信息
上了生产环境,这样编译:
[root@xhu-vm 5]# cc debug.c -o debug
执行结果:
[root@xhu-vm 5]# ./debug
[root@xhu-vm 5]#
没有输出debug信息
1.2 编译
1.3 优化和汇编
2.链接过程
2.1 在debug的例子上在加上一句 打印的测试代码,使用 编译-链接-执行 来完成这个例子
#include <stdio.h> main() { #ifdef DEBUG fprintf(stderr,"debug infomation \n"); #endif fprintf(stderr,"just a test!\n"); }
a. 使用 [root@xhu-vm 5]# gcc -c debug.c 生成.o 目标文件 debug.o
b. 使用 [root@xhu-vm 5]# gcc debug.o -o debug 将目标文件链接成可执行文件
c. 查看结果
[root@xhu-vm 5]# ./debug
just a test!
[root@xhu-vm 5]#
d.使用dumpobj 反编译.o 目标文件
[root@xhu-vm 5]# objdump -d debug.o debug.o: file format elf32-i386 Disassembly of section .text: 00000000 <main>: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 ec 08 sub $0x8,%esp 6: 83 e4 f0 and $0xfffffff0,%esp 9: b8 00 00 00 00 mov $0x0,%eax e: 83 c0 0f add $0xf,%eax 11: 83 c0 0f add $0xf,%eax 14: c1 e8 04 shr $0x4,%eax 17: c1 e0 04 shl $0x4,%eax 1a: 29 c4 sub %eax,%esp 1c: 83 ec 08 sub $0x8,%esp 1f: 68 00 00 00 00 push $0x0 24: ff 35 00 00 00 00 pushl 0x0 2a: e8 fc ff ff ff call 2b <main+0x2b> 2f: 83 c4 10 add $0x10,%esp 32: c9 leave 33: c3 ret [root@xhu-vm 5]#
2.2 动态链接和静态链接
静态链接:[root@xhu-vm 5]# gcc debug.o -o debug
动态链接:[root@xhu-vm 5]# gcc -s debug.c -o debug.s
运行:
[root@xhu-vm 5]# ./debug.s
just a test!
[root@xhu-vm 5]#
我们可以看到 静态链接 产生的文件体积要小
[root@xhu-vm 5]# ll total 20 -rwxr-xr-x 1 root root 4818 Jun 7 06:41 debug -rw-r--r-- 1 root root 127 Jun 7 06:37 debug.c -rw-r--r-- 1 root root 920 Jun 7 06:37 debug.o -rwxr-xr-x 1 root root 3000 Jun 7 07:04 debug.s [root@xhu-vm 5]#
2.3 用GCC 生成可执行文件
例子目的: 按照c 项目的目录结构,建立inc,src,lib等目录,建立.h, .c,.lib文件 ,完成调用自己lib中的加法功能,其他程序可以静态链接这个.a 库文件 ,并使用其中的方法
a. 目录结构
[root@xhu-vm pro1]# pwd /root/c_project/source code/5/pro1 [root@xhu-vm pro1]# ll total 12 drwxr-xr-x 2 root root 4096 Jun 7 08:13 inc drwxr-xr-x 2 root root 4096 Jun 7 08:13 lib drwxr-xr-x 2 root root 4096 Jun 7 08:18 src
b. 在src 目录下写 tool.c ,并使用 gcc 将其编译成.o的目标文件
[root@xhu-vm src]# more tool.c #include <stdio.h> int add(int x ,int y) { return x+y; } [root@xhu-vm src]#
[root@xhu-vm src]# cc -c tool.c [root@xhu-vm src]# ll total 8 -rw-r--r-- 1 root root 58 Jun 7 08:18 tool.c -rw-r--r-- 1 root root 684 Jun 7 08:21 tool.o [root@xhu-vm src]#
c. 将 tool.o形成 库文件,方便其他程序调用add方法,其中 lib tools.a 的命名必须规范,以lib开头,以.a结尾
[root@xhu-vm src]# ar rv libtools.a tool.o ar: creating libtools.a a - tool.o [root@xhu-vm src]#
d. 编写tool1.c 实现减法操作
[root@xhu-vm src]# vi tool1.c #include <stdio.h> int sub(int x,int y) { return x-y; }
编译成.o 文件
[root@xhu-vm src]# ll total 20 -rw-r--r-- 1 root root 824 Jun 7 08:28 libtools.a -rw-r--r-- 1 root root 57 Jun 7 08:31 tool1.c -rw-r--r-- 1 root root 689 Jun 7 08:31 tool1.o -rw-r--r-- 1 root root 58 Jun 7 08:18 tool.c -rw-r--r-- 1 root root 684 Jun 7 08:21 tool.o [root@xhu-vm src]#
将tool1.o放到libtools.a库文件中
[root@xhu-vm src]# ar rv libtools.a tool1.o a - tool1.o
查看 libtools.a包含哪些目标文件,可见加法和减法的目标文件都 已经放到库文件中去了
[root@xhu-vm src]# ar tv libtools.a rw-r--r-- 0/0 684 Jun 7 08:21 2011 tool.o rw-r--r-- 0/0 689 Jun 7 08:31 2011 tool1.o [root@xhu-vm src]#
将库文件 移动到lib下
[root@xhu-vm src]# mv libtools.a ../lib/
e.在inc下 编写 .h 头文件
[root@xhu-vm inc]# vi my.h #define VALUE 100
f. 编写a.c
[root@xhu-vm src]# vi a.c #include <stdio.h> #include "my.h" main() { fprintf(stderr,"VALUE + 10=%d\n",add(VALUE,10)); }
g. 编译 a.c 生成a.o , -I 指定头文件路径
[root@xhu-vm src]# gcc -c -I../inc a.c [root@xhu-vm src]# ll total 24 -rw-r--r-- 1 root root 96 Jun 7 08:44 a.c -rw-r--r-- 1 root root 964 Jun 7 08:46 a.o -rw-r--r-- 1 root root 57 Jun 7 08:31 tool1.c -rw-r--r-- 1 root root 689 Jun 7 08:31 tool1.o -rw-r--r-- 1 root root 58 Jun 7 08:18 tool.c -rw-r--r-- 1 root
h. 链接并执行,查看结果 ,-L 指定库文件路径 -l 指定库文件名称
[root@xhu-vm src]# gcc a.o -L../lib -ltools -o a [root@xhu-vm src]# ./a VALUE + 10=110 [root@xhu-vm src]#
2.4 用GCC 生成 动态链接库
例子目的: 使用gcc生成一个.so的动态链接库
a. 建立 pro2目录,在下面建立一个 包含加法 运算的 a.c文件
[root@xhu-vm pro2]# vi a.c { main() #include <stdio.h> int add(int x,int y) { return x+y; }
b. 使用 -fPIC 编译源文件,生成可以重定位的目标代码,对于需要被动态链接的函数库,这点尤其重要。
[root@xhu-vm pro2]# gcc -fPIC -c a.c [root@xhu-vm pro2]# ll total 8 -rw-r--r-- 1 root root 57 Jun 8 13:14 a.c -rw-r--r-- 1 root root 681 Jun 8 13:15 a.o [root@xhu-vm pro2]#
c. 使用gcc -shared -o libabc.so xxx.o 生成动态链接库 ,其中 lib abc.so 的命名必须规范,以lib开头,以.so结尾
[root@xhu-vm pro2]# gcc -shared -o libabc.so a.o [root@xhu-vm pro2]# ll total 16 -rw-r--r-- 1 root root 57 Jun 8 13:14 a.c -rw-r--r-- 1 root root 681 Jun 8 13:15 a.o -rwxr-xr-x 1 root root 4152 Jun 8 13:22 libabc.so
d. 使用动态链接库
2种方式:
1. 一是通过设置环境变量LD——LIBRARY_PATH的方式 (这种方式比较常用 )
2. 二是通过dlopen系列系统调用动态打开的方式
使用方式1, 先写b.c ,包含main
[root@xhu-vm pro2]# vi b.c #include <stdio.h> main() { fprintf(stderr,"%d\n",add(1,1)); }
e. 编译b.c 文件
[root@xhu-vm pro2]# gcc -c -O b.c [root@xhu-vm pro2]# ll total 24 -rw-r--r-- 1 root root 57 Jun 8 13:14 a.c -rw-r--r-- 1 root root 681 Jun 8 13:15 a.o -rw-r--r-- 1 root root 64 Jun 8 13:33 b.c -rw-r--r-- 1 root root 936 Jun 8 13:34 b.o -rwxr-xr-x 1 root root 4152 Jun 8 13:22 libabc.so
f. 生成可执行文件
[root@xhu-vm pro2]# gcc b.o -L./ -labc -s -o b [root@xhu-vm pro2]# ll total 28 -rw-r--r-- 1 root root 57 Jun 8 13:14 a.c -rw-r--r-- 1 root root 681 Jun 8 13:15 a.o -rwxr-xr-x 1 root root 3272 Jun 8 13:35 b -rw-r--r-- 1 root root 64 Jun 8 13:33 b.c -rw-r--r-- 1 root root 936 Jun 8 13:34 b.o -rwxr-xr-x 1 root root 4152 Jun 8 13:22 libabc.so [root@xhu-vm pro2]#
-L 指定库文件所在的目录
-l 指定库文件的名字 ,系统会搜索 libabc.a 静态库文件 和 libabc.so 的动态库文件
-s 只搜索扩展名为.so的库文件
-o 指定输出文件名字
g. 运行可执行文件,报错了 找不到 共享的库文件,原因是我们没有设置环境变量
[root@xhu-vm pro2]# ./b ./b: error while loading shared libraries: libabc.so: cannot open shared object file: No such file or directory [root@xhu-vm pro2]#
设置了 LD_LIBRARY_PATH 这个环境变量 指定动态库的位置 后 我们得到了 1+1=2 的结果
[root@xhu-vm pro2]# export LD_LIBRARY_PATH=./ [root@xhu-vm pro2]# ./b 2 [root@xhu-vm pro2]#
使用方式2 : 使用了系统的dlopen系列函数 (程序启动的时候并不加载,等需要使用的时候再加载)
[root@xhu-vm pro2]# vi c.c int *pdata = NULL; #include <stdio.h> #include <dlfcn.h> int (*fcn)(int,int) = NULL; int load(const char *libname) { void *handle; handle = dlopen(libname, RTLD_NOW); if (handle == NULL) { fprintf(stderr,"Failed to load %s: %s\n",libname, dlerror()); return 1; } fcn = dlsym(handle,"add"); if (fcn == NULL) { fprintf(stderr,"%s\n",dlerror()); dlclose(handle); return 1; } /* 加载完不能dlclose,必须等到不再使用从handle中加载出的任何东西时才能dlclose*/ return 0; } int main() { if (load("./libabc.so")) { return 1; } int result = fcn(2,2); printf("%d\n",result); return 0; }
[root@xhu-vm pro2]# gcc -o c -ldl c.c [root@xhu-vm pro2]# ./c 4 [root@xhu-vm pro2]#
Note: 使用dlsym 函数不仅可以得到 动态库中 函数的指针,也可以得到 动态库中的全局变量的指针,从而得到全局变量的值,我们产品的agent framework 就是这样的,在so加载的时候用 dlsym 方式得到 一个全局变量aa, 这个aa 代表了 所有能操的op_list 集合,然后用 得到函数指针,最后调用方法, 下面有个例子
a.在 so 中定义2个全局变量,一个是float,一个是char[],在 caller中得到他们的地址
a.c
#include <stdio.h> float test=123.4; char test2[]="xhu"; int add(int x,int y) { return x+y; }
编译 : gcc -fPIC -c a.c ->> 得到a.o
打包so gcc -shared -o libabc.so a.o
测试程序 c.c
#include <stdio.h> #include <dlfcn.h> char* fcn=NULL; float* ff=NULL; int load(const char *libname) { void *handle; handle = dlopen(libname, RTLD_LAZY); if (handle == NULL) { fprintf(stderr,"Failed to load %s: %s\n",libname, dlerror()); return 1; } fcn =(char*)dlsym(handle,"test2"); ff = (float*)dlsym(handle,"test"); if (fcn == NULL) { fprintf(stderr,"%s\n",dlerror()); dlclose(handle); return 1; } /* 加载完不能dlclose,必须等到不再使用从handle中加载出的任何东西时才能dlclose*/ return 0; } int main() { if (load("../lib/libabc.so")) { return 1; } char* result = fcn; printf("%s\n",result); float* result2 = ff; printf("%f\n",*result2); return 0; }
编译: gcc -o c -ldl c.c >> 得到c
执行:
[root@egovmo03 src]# ./c
xhu
123.400002
打完收工
发表评论
-
static作用(修饰函数、局部变量、全局变量)
2016-06-05 15:45 1176在C语言中,static的字面意思很容易把我们导入歧途 ... -
typedef
2014-06-08 14:27 899用 typedef 定义类型 10 用 typedef ... -
linux C语言系列--第七讲--信号
2012-07-22 11:14 1390啦啦 -
libxml 解析xml
2012-07-18 21:49 0TODO -
c 函数的返回值
2012-07-16 06:10 1438无法把指针变量本身传递给一个函数 void Get ... -
如何编写有多个返回值的C语言函数
2012-02-21 22:25 0我们知道C语言函数的返回值是通过函数中的return语句来实现 ... -
c语言中的字符数组与字符串
2012-02-21 14:15 70921、字符数组的定义与初始化 字符数组的初始化,最容易理解 ... -
linux C语言系列--第六讲--进程
2011-07-31 18:18 1916守护进程概述 ... -
linux C语言系列--第五讲--函数
2011-06-22 08:09 1244可变参数列表: 例子:写一个函数,求给定所 ... -
全面复习linux C语言系列--第四讲--程序调试
2011-06-10 00:28 1383出错处理 • 1.使用标准错误输出 ... -
全面复习linux C语言系列--第三讲--make的使用
2011-06-09 07:42 1470make 概述 Make ... -
全面复习linux C语言系列--第一讲--基础知识
2011-06-07 23:27 1487看别人code的时候 ... -
Windows下用Eclipse搭建C/C++开发环境
2010-01-07 21:54 1187http://www.iteye.com/topic/5605 ...
相关推荐
在本资源"AKA Linux编程系列讲座第二期的所有资料"中,您将深入学习Linux操作系统下的编程技术。这个系列讲座的第二期是一个精心设计的教程,旨在为初学者提供一个全面且详细的指导,涵盖了大量的理论知识和实践案例...
#### 第2章 Shell编程基础 - **目标**: - 熟悉Linux系统下的编辑环境。 - 熟练进行shell编程。 - **主要知识点**: - **使用vi编辑文件**:包括基本模式切换、文本编辑操作等。 - **使用Emacs编辑文件**:介绍...
在本实验报告中,我们将深入探讨Linux操作系统下的C语言编程,包括如何使用vi编辑器、GCC编译器、gdb调试器以及如何编写和管理多源文件项目。实验旨在提升学生对Linux环境下的编程能力,熟悉系统调用,以及学会使用...
书中提到了UNIX系统、GNU编译器集合(GCC)和LLVM项目、Linux系统下的编译环境,以及PC上的命令行编译器和集成开发环境(IDE)等不同平台的编译工具。 5. 本书的组织结构按照学习C语言的步骤进行,从简单的程序示例...
《Linux环境C程序设计》是徐诚先生在清华大学出版社出版的第二版教材,该书深入浅出地介绍了在Linux操作系统下进行C语言编程的基础知识和高级技巧。此资源包含源码和PPT,为读者提供了丰富的实践材料和教学辅助资料...
- **Gcc编译器**:GNU C Compiler,用于将C/C++源代码编译为可执行文件。 - **Gcc编译流程解析**:预处理、编译、汇编、链接四个阶段。 - **Gcc编译选项分析**:如`-Wall`显示所有警告信息,`-g`添加调试信息。 - ...
- **第2、3周**:重点是学习在Linux环境下进行C语言编程。 - **周一**:介绍C程序设计的基本概念,包括流程图表示算法、数据类型等。 - **周二**:讲解循环控制语句、分支结构程序设计等。 - **周三**:深入理解...
从给定的文件信息中,我们可以总结出一系列与NOI(National Olympiad in Informatics,全国青少年信息学奥林匹克竞赛)笔试复习相关的IT知识点,主要集中在Linux操作系统的基本操作、编程语言概念以及程序调试等方面...
通过这些题目,读者可以复习和巩固Linux系统的基础知识,包括文件操作、进程管理、内存管理、GCC编译器的使用、GDB调试技巧以及C语言编程规范和逻辑判断等内容。这将有助于提高Linux软件工程师的技能水平和应对考试...
10. **编译与调试**:GCC编译器的使用、Makefile的编写,以及GDB调试器的运用,帮助开发者有效地构建和调试程序。 随书提供的源码和PPT资料进一步加强了学习体验。源码涵盖了书中示例,读者可以亲自运行和分析,...
\n\n1.2 **环境与工具**:报告中使用的操作系统为Ubuntu,这是一种广泛使用的Linux发行版,支持各种编程工具,如GCC(GNU Compiler Collection)作为编译器,GDB(GNU Debugger)用于调试,以及其它辅助工具如grep和...
开发工具包括Visual Studio Code、VI/VIM/GPEDIT以及GCC编译器。这些工具提供了编写、编辑、调试和构建C程序的平台。 通过对"hello.c"的生命周期的研究,张璐不仅复习了计算机系统的各个环节,还对进程管理有了更深...