2015.1.22

c高级的环境搭建:
GCC编译器:
全称 GNU CC,是GNU工具(tool chain)的一种,源码编译成机器码,gcc的编译依赖于很多小工具
4.3.3和3.4.3版本的比较稳定

GCC编译分为四个步骤:(用WC命令可以分别查看每个阶段代码的大小,可以比较一下,ls -l 也能看出大小)
1.预处理 ->cpp预处理文件*.i gcc -E
2.编译 ->cc1汇编文件*.s gcc -S
3.汇编 ->as汇编文件*.o gcc -c
4.链接 ->ld可执行文件*.exe (将多个.o文件组合成可执行的应用程序,连接器需要知道这种目标格式,以便工作)
gcc -O或者-O2是编译优化的
gcc -I dir 指定添加的头文件目录,默认在/usr/include/
lib + 库名.a

readelf hello -h 显示可执行文件的信息
strip 丢弃目标文件的全部或者特定符号,减小文件体积,发布代码的时候可以用

交叉编译,是在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。
这个编译过程就叫交叉编译。
比如:arm—cortex-a8,arm-linux-gcc
GDB调试工具:能对执行程序进行源码或者汇编级调试
root@lg-desktop:~/test/gdb# gcc -g e.c -o e 生成调试信息
root@lg-desktop:~/test/gdb# gdb e 进入调试界面
GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/test/gdb/e...done.
(gdb) l (l查看文件,每次只能看10行)
1 #include <stdio.h>
2 #include <string.h>
3 #define N 50
4 int main()
5 {
6 int t;
7 char s1[N];
8 char s2[N];
9
10 printf(">");
(gdb) l
11 scanf("%s%s",s1,s2);
12 t = strcmp(s1,s2);
13 if ( 0 == t)
14 printf("s1 = s2\n");
15 else if(t > 0)
16 printf("s1 > s2\n");
17 else
18 printf("s1 < s2\n");
19 return 0;
20
(gdb) l
21 }
(gdb) b 11 在11行设置断点
Breakpoint 1 at 0x4006b8: file e.c, line 11.
(gdb) info b 查看断点信息
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004006b8 in main
(gdb) r 运行,会停在第一个断点处
Starting program: /root/test/gdb/e

Breakpoint 1, main () at e.c:11
11 scanf("%s%s",s1,s2);
(gdb) n 单步运行
>2 3
12 t = strcmp(s1,s2);
(gdb) s 单步运行
0x00007ffff7adc5a0 in strcmp () from /lib/libc.so.6
at e.c:11
(gdb) p t 查看变量t的值,
$1 = 0
(gdb) c 恢复运行
Continuing.
s1 > s2

Program exited normally.
(gdb) help 获取帮助
List of classes of commands:

aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands

Type "help" followed by a class name for a list of commands in that class.
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb) q (q退出)
root@lg-desktop:~/test/gdb#

调试的一段程序,总结下:
数组要特别注意下标的范围 注意!注意!注意!

1 #include<stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int display1(char *string);
6 int display2(char *string);
7
8 int main(int argc,char **argv)
9 {
10 char string[]="Embedded Linux";
11 display1(string);
12 display2(string);
13
14 }
15 int display1(char *string)
16 {
17 printf("the original string is %s\n",string);
18 }
19
20 int display2(char *string1)
21 {
22 char *string2;
23 int size,i;
24 size = strlen(string1); //数组长度为14
25 string2 = (char *)malloc(size+1);
26 for(i = 0;i < size;i++)
27 string2[size-i] = string1[i]; // 应该是string2[size-1-i] = string1[i];
28 string2[size+1] = '\0'; // 应该是string2[size] = '\0';
29 printf("the string afterward is %s\n",string2);
30 free(string2);
31 }

源程序运行结果:
root@lg-desktop:~/test/gdb# gcc gdb.c -o gdb -g
root@lg-desktop:~/test/gdb# ./gdb
the original string is Embedded Linux
the string afterward is //这里得不到真确的结果
root@lg-desktop:~/test/gdb#

开始调试:
Reading symbols from /root/test/gdb/gdb...done.
(gdb) b 30 设置断点
Breakpoint 1 at 0x400794: file gdb.c, line 30.
(gdb) r
Starting program: /root/test/gdb/gdb
the original string is Embedded Linux
the string afterward is

Breakpoint 1, display2 (
string1=0x7fffffffe5d0 "Embedded Linux") at gdb.c:30
30 free(string2);
(gdb) n
31 }
(gdb) p string2[0]
$1 = 0 '\000' //字符传首地址为的值为\0,不是想要的

修改原函数:
27 string2[size-i] = string1[i]; // 应该是string2[size-1-i] = string1[i];
28 string2[size+1] = '\0'; // 应该是string2[size] = '\0';

调试:

(gdb) b 28
Breakpoint 1 at 0x400768: file gdb.c, line 28.
(gdb) r
Starting program: /root/test/gdb/gdb
the original string is Embedded Linux

Breakpoint 1, display2 (
string1=0x7fffffffe5d0 "Embedded Linux") at gdb.c:28
28 string2[size] = '\0';
(gdb) p string2[0]
$1 = 120 'x'
(gdb) p string2[14]
$2 = 0 '\000'
(gdb

最终程序运行结果:

root@lg-desktop:~/test/gdb# ./gdb
the original string is Embedded Linux
the string afterward is xuniL deddebmE

gdb的另一个重要功能是调试死机和段错误;很重要哦!!!!!
例子:首先编写一个错误的程序 core.c 名字随便写
1 #include<stdio.h>
2 core_function(void)
3 {
4 unsigned char *ptr = 0x00;
5 *ptr = 0x00;
6 }
7
8 int main(void)
9 {
10 core_function();
11 return 0;
12
13 }
~下面是生成core(这个名字是系统固定的)文件的步骤:
root@lg-desktop:~/file# gcc core.c -g //1.编译core.c文件
root@lg-desktop:~/file# ulimit -c unlimited //2.设置core大小为无限
root@lg-desktop:~/file# ulimit unlimited //3.设置文件大小为无限
root@lg-desktop:~/file# ./a.out //4.运行编译后的文件,生成下面的core文件
Segmentation fault (core dumped) //5.生成core文件
root@lg-desktop:~/file# gdb ./a.out core //6.gdb调试,会显示错误在哪一行
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004004d4 in core_function () at core.c:5
5 *ptr = 0x00; 7.表示停在第5行,第4行出错了
(gdb)

软件工程工具:make,cvs,subvision

make 是一个工程管理工具,需要通过Makefile实现(注意是大写的M)
下面是实例演示:包含4个.c文件,main.c,f1.c,f2.c,f3.c,最后编写Makefile脚本
.C文件和Makefile需要放在同一个文件夹下面

main.c****************************
1 #include <stdio.h>
2 void enter_string(char str[]);
3 void delete_string(char str[],char ch);
4 void print_string(char str[]);
5
6 int main(void)
7 {
8 char c,str[50];
9 enter_string(str);
10 printf("the char to be deleted is:");
11 scanf("%c",&c);
12 delete_string(str,c);
13
14 }
f1.c**************************************
1 #include <stdio.h>
2 void enter_string(char str[])
3 {
4 printf("input a string:");
5 gets(str);
6
7 }
f2.c**************************************
1 void delete_string(char str[],char ch)
2 {
3 int i,j;
4 for(j = i = 0;str[i] != '\0';i++)
5 {
6 if(str[i] != ch)
7 str[j++]=str[i];
8 str[j]='\0';
9 }
10
11 }
f3.c****************************************
1 #include <stdio.h>
2 void print_string(char str[])
3 {
4 printf("result:%s\n",str);
5
6 }

Makefile***************************Makefile编写很严格,两边不能有空格,切记!

下面的all是目标文件,后面的是依赖文件
生成目标的命令行,可有多行,到下一组命令开始白哦是结束 //1和2组成一个组
1 all: main.o f1.o f2.o f3.o
2 gcc -o all main.o f1.o f2.o f3.o
3 main.o: main.c
4 gcc -c main.c -o main.o
5 f1.o: f1.c
6 gcc -c f1.c -o f1.o
7 f2.o: f2.c
8 gcc -c f2.c -o f2.o
9 f3.o: f3.c
10 gcc -c f3.c -o f3.o
11 clean:
12 rm main.o f1.o f2.o f3.o
13

四个点C文件一起编译,查看有没有错:

root@lg-desktop:~/file# gcc -o test main.c f1.c f2.c f3.c
/tmp/ccmCZYiO.o: In function `enter_string':
f1.c:(.text+0x26): warning: the `gets' function is dangerous and should not be used.
root@lg-desktop:~/file# ls
a.out f1.c f3.c fifo_read.c test
core.c f2.c fife_write.c main.c write_lock.c

Makefile 编写好之后,直接运行make:
root@lg-desktop:~/file# make //运行make
gcc -c main.c -o main.o
gcc -c f1.c -o f1.o
gcc -c f2.c -o f2.o
gcc -c f3.c -o f3.o
gcc -o all main.o f1.o f2.o f3.o
f1.o: In function `enter_string':
f1.c:(.text+0x26): warning: the `gets' function is dangerous and should not be used.
root@lg-desktop:~/file# ls
all core.c f2.c f3.o main.c test
a.out f1.c f2.o fife_write.c main.o write_lock.c
core f1.o f3.c fifo_read.c Makefile

上面是整体过程,下面是分析:

Makefile中的变量:
1.变量代表的是字符串,在Makefile中执行的时候会自动原样的展开在所有使用的地方
2.变量可以使用在目标,依赖目标,命令或者其他部分中
3.变量可以包含字符,数字,下划线
4.变量对大小写敏感,传统的变量是全大写的
5.命令行里面的变量优先级最高,预定义最低

变量定义的格式:
变量名 赋值符号 变量的值

赋值符号有三种:

= 直接将后面的字符串赋给变量
:= 后面跟变量,将它的内容赋给变量
+= 变量原来的值+空格+后面的字符串=>新的变量值

$* 不包含扩展名的目标名称
$+ 所有依赖文件,并已空格分开,
$< 第一个依赖文件的名称
$? 所有依赖文件,并已空格分开,主要是所有改过的文件
$@ 目标的完整名称
$^ 所有依赖文件,并已空格分开,不包含重复的依赖文件

条件编译:
ifeq
ifneq
ifdef
ifndef
endif //结束符

for k in $(DIRS);do 循环体 done

makefile函数

SRCS = $(wildcard *.c) //将当前目录下的所有点C文件赋给SRCS
SRCS = $(patsubst %.c,%.o,<目录或者文件等>) //将<目录或者文件等>中的所有.c文件替换成.o文件并赋给SRCS

%.o: %.c
gcc -c $< -o $@
上面两句的意思是将任意的.c文件转换成.o文件!

为了避免和文件重名的情况,可以使用一个特殊的标记“.PHONY”来显示的指明一个目标为“伪目标”
.PHONY: all

经过变量替换处理,下面两个Makefile的功能是相同的:

Makefile1:
1 all: main.o f1.o f2.o f3.o
2 gcc -o all main.o f1.o f2.o f3.o
3 main.o: main.c
4 gcc -c main.c -o main.o
5 f1.o: f1.c
6 gcc -c f1.c -o f1.o
7 f2.o: f2.c
8 gcc -c f2.c -o f2.o
9 f3.o: f3.c
10 gcc -c f3.c -o f3.o
11 clean:
12 rm main.o f1.o f2.o f3.o
13
Makefile2:
1 .PHONY: all
2 SRCS = $(wildcard *.c)
3 DD = $(patsubst %.c,%.o,$(SRCS))
4 all: $(DD)
5 gcc -o all $+
6 echo $+
7 %.o: %.c
8 gcc -c $< -o $@
9 clean:
10 rm -rf all $(DD)
11

文件锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程能在文件的同一部分建立读取锁。
而写入锁又称为排斥锁,在任何时刻只能有一个进程在文件的某个部分建立写入锁,在文件的同一部分不能同时
建立读取锁和写入锁!!!!

lockf() 函数用于对文件施加建议性锁
fcntl() 函数不仅可以施加建议性锁,还可以施加强制锁,同时,fcntl还能对文件的某一记录上锁,也就是记录锁
同时它还是一个通用的函数,还可以对已打开的文件描述符进行各种操作,不仅包括文件锁,还包括获取和设置文件描述符
标志,文件描述符的复制等很多功能

int fcntl(int fd,int cmd,struct flock *lock)
0:成功 -1:出错

struct flock
{
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;

}

文件记录锁功能的源代码:

int lock_set(int fd,int type)
{
struct flock old_lock,lock;
locd.l_whence = SEEK_SET;
lock.l_start = 0;
lock.1_len = 0;
lock.l_type = type;
lock.l_pid = -1;

/*判断文件是否可以上锁*/
fcntl(fd,F_GETLK,&lock);

if((lock.l_type != F_UNLCK)
{
if(lock.l_type == F_RDLCK) /*该文件*/
{
printf("read lock already set by %d\n",lock.l_pid);
}
else if(lock.l_type == F_WRLCK)
{
printf(" write lock already set by %d\n",lock.l_pid);
}
}
/*l_type可能已被F_GETLK修改过*/
lock.l_type = type;
/*根据不同的type值进行阻塞上锁或解锁*/
if((fcnl(fd,F_SETLKW,&lock)) < 0)
{
printf("lock failed:type = %d\n",lock.l_type);
return 1;

}
switch(lock.l_type)
{
case F_RDLCK:
{
printf("read lock set by %d\n",getpid());
}
break;
case F_WRLCK:
{
printf("write lock set by %d\n",getpid());
}
break;
case F_UNLCK:
{
printf("Release lock by %d\n",getpid());
return 1;
}
break;
default:
break;

}
return 0;

}

下面的实例是文件写入锁的测试用例,首先创建一个hello,之和对其写入锁和释放写入锁
其中包含了上一面的程序lock_set(fd,F_WRLCK);
#include <unistd.h>
2 #include <sys/file.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #inlcude "lock_set.c"
8
9 int main(void)
10 {
11 int fd;
12 fd = open("hello",O_RDWR | O_CREAT,0644);
13 if(fd < 0)
14 {
15 printf("open file error\n");
16 exit(1);
17 }
/*给文件上读取锁*/
18 lock_set(fd,F_WRLCK);
19 getchar();
/*给文件解锁*/
20 lock_set(fd,F_UNLCK);
21 getchar();
22 close(fd);
23 exit(0);
24

select()和poll()的I/O多路转接模型是处理I/O复用的一个高效的方法。
int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set*exeptfds,struct timeval *timeout)
int poll(struct pollfd *fds,int numfds,int timeout)

下面程序是调用select()函数来监听3个终端的输入(分别定向到两个管道文件的虚拟终端以及
主程序所运行的虚拟终端),并分别进行相应的处理,

///multiplex_select.c

1 #include <fcn1.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <time.h>
6 #include <errno.h>
7
8 #define MAX_BUFFER_SEZE 1024 缓冲区大小
9 #define IN_RILES 3 多路复用输入文件数目
10 #define TIME_DELAY 60 超时值秒数
11 #define MAX(a.b) ((a > b) ? (a):(b))
12
13 int main(void)
14 {
15 int fds[IN_FELES];
16 char buf[MAX_BUFFER_SIZE];
17 int i,res,real_read,maxfd;
18 struct timeval tv;
19 fd_set inset,tmp_inset;
20 /*首先以只读非阻塞方式打开两个管道文件*/
21 fds[0] = 0;
22 if((fds[1] = open("in1",O_RDONLY | O_NONBLOCK))<0)
23 {
24 printf("open in1 error\n");
25 return 1;
26 }
27 if((fds[2] = open("in2",O_RDONLY | O_NONBLOCK))<0)
28 {
29 printf("open in2 error\n");
30 return 1;
31 }
32 /*取出两个文件描述符中的较大者*/
33 maxfd = MAX(MAX(fds[0],fds[1]),fd[2]);
/*初始化读集合inset,并在读集合中加入相应的描述集*/
34 FD_ZERO(&inset);
35 for(i = 0;i < IN_FILES;i++)
36 {
37 FD_SET(fds[i],&inset);
38 }
39 FD_SET(0,&inset);
40 tv.tv_sec = TIME_DELAY;
41 tv.tv_usec = 0;
42 /*循环测试该文件描述符是否准备就绪看,并调用select函数对相关文件描述符做对应操作*/
43 while(FD_ISSET(fds[0],&inset) || FD_ISSET(fds[1],&inset)||FD_ISSET(fds[0],&inset))
44 {
/*文件描述符的备份,这样可以避免每次进行初始化*/
45 tmp_inset = inset;
46 res = select(maxfd + 1,&tmp_inset,NULL,NULL,&tv);
47 switch(res)
48 {
49 case -1:
50 {
51 printf("select error\n");
52 return 1;
53 }
54 break;
55 case 0:
56 {
57 printf("time out\n");
58 return 1;
59 }
60 break;
61 default:
62 {
63 for(i = 0;i < IN_FILES;i++)
64 {
65
66 memset(but,0,MAX_BUFFER_SEZE);
67 real_read = read(fds[i],buf,MAX_BUFFER_SEZE);
68 if(real_read < 0)
69 {
70 if(error != EAGAIN)
71 return 1;
72 }
73 else if(!real_read)
74 {
75 close(fds[i]);
76 FD_LCR(fds[i],&inset);
77
78 }
79 else
80 {
81 if(i == 0)
82 {
/*主程序终端控制*/
83 if((buf[0]=='q') ||(buf[0] == 'Q'))
84 return 1;
85 }
86 else
87 {
88 buf[real_read] = '\0';
89 printf("%s",buf);
90 }
91 }
92
93 }
94 }
95 }
96 break;
97 }
98
99 return 0;
100}
**********************************************************************************************************************************************************
**********************************************************************************************************************************************************
**********************************************************************************************************************************************************

GCC,GDB,Makefile和IO复用函数的更多相关文章

  1. [00]APUE:GCC / GDB / Makefile

    http://blog.csdn.net/haoel/article/category/9197 http://blog.csdn.net/haoel/article/details/2886  生成 ...

  2. 网络编程API-下 (I/O复用函数)

    IO复用是Linux中的IO模型之中的一个,IO复用就是进程预先告诉内核须要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理.从而不会在单个IO上堵塞了. Linu ...

  3. Linux网络编程-IO复用技术

    IO复用是Linux中的IO模型之一,IO复用就是进程预先告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理,从而不会在单个IO上阻塞了.Linux中,提 ...

  4. Libevent的IO复用技术和定时事件原理

    Libevent 是一个用C语言编写的.轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相当精炼.易 ...

  5. LINUX网络编程 IO 复用

    参考<linux高性能服务器编程> LINUX下处理多个连接时候,仅仅使用多线程和原始socket函数,效率十分低下 于是就出现了selelct poll  epoll等IO复用函数. 这 ...

  6. 网络IO-阻塞、非阻塞、IO复用、异步

    网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...

  7. IO复用_select函数

    select函数: #include <sys/select.h> #include <time.h> #include <sys/types.h> #includ ...

  8. 【Unix网络编程】chapter6 IO复用:select和poll函数

    chapter6 6.1 概述 I/O复用典型使用在下列网络应用场合. (1):当客户处理多个描述符时,必须使用IO复用 (2):一个客户同时处理多个套接字是可能的,不过不叫少见. (3):如果一个T ...

  9. gcc与makefile编译 BY 四喜三顺

    gcc编译控制过程:(假设源代码为a.c)(1)源文件到预处理文件:    gcc -E -o a.cxx a.c    a.cxx显示调用哪些头文件(2)生成汇编代码:              g ...

随机推荐

  1. 输出有序数组的中两个元素差值为指定值diff的两个元素

    题目: 输出有序数组的中两个元素差值为指定值diff的两个元素. 思路: 这与输出两个元素的和的值为一定值类似,需要两个指针,不同的是:指针不是一左一右,而是一前一后. 如果差值等于diff,则返回: ...

  2. from __future__ import absolute_import

    from __future__ import absolute_import 这样以后:局部的包将不能覆盖全局的包, 本地的包必须使用相对引用了. 例: from celery import Cele ...

  3. SELECTION-SCREEN 文本丢失

    最近有点无聊....随便找点东西填了... 自从系统上线,经常出现程序的的文本丢失,然后选择界面就变成英文的了....一直在出现,就是解决不了,不知道到底是哪里的问题 严重怀疑是服务器上文件丢失... ...

  4. java 分析方法调用过程

    StackTraceElement[] s = new Exception().getStackTrace(); for(int i=0;i<s.length;i++) System.out.p ...

  5. nssm在windows服务器上部署nodejs,coffee启动方式

    本想用forever / pm2 来部署nodejs, 百度后发现只能在Linux系统上使用,window上没法使用,兜一圈后又转nssm了.... 在Linux上,可以轻松的使用forever或者p ...

  6. Play Framework介绍:主要概念(转)

    Play Framework是一个Rails风格的Full-stack Java Web框架. MVC模型 Play应用遵循Web架构使用的MVC架构模式. 它将应用分离到不同的层中:表现层(Pres ...

  7. PHP中MySql函数收集

    1.array mysql_fetch_assoc ( resource $result ) 从结果集中取得一行作为关联数组 说明:  返回对应结果集的关联数组,并且继续移动内部数据指针. 参数:re ...

  8. 使用VideoView播放视频

    为了在Android应用中播放视频,Android提供了VideoView组件,它就是一个位于android.widget包下的组件,它的作用与ImageView类似,只是ImageView用于显示图 ...

  9. UTF-8

    UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码.由Ken Thompson于1992年创建.现在已经标准化为 ...

  10. js打印数组查看

    alert() 是不能查看数组,对象的console.log(数组变量); 然后你用火狐的friebug 在控制台查看