Linux精英,聚会Intel(转自袁萌CSDN博客)
12 25, 2008 Linux
众所周知,随着社会计算力的大集中(如Cloud计算),“迷你本”和Intel倡导的MID(移动互联设备)必然兴起,这是发展的大趋势。因而,Intel的Moblin(Moble Linux)计划凸现其重要性。在小小的“迷你本”和MID上,周边的硬件环境变了,怎么跑Linux?但是,在2009年,微软Windows 7和Linux必然交锋于这个新领域。怎么办?
12月23日,Linux世界的第2号人物Alan Cox宣布离开Red Hat前往Intel工作,表面看看来,令人不解,实际上,很有道理。当今,红帽(Red Hat)已经发展成为一个很典型(几乎是这样)的开源公司,运营很规范,发展很健康。但是,发展成熟,也就意味着要发生变化。我们把话说明白了,这就意味着Linux很底层的问题,对于红帽的经营而言,将不再是最紧迫的问题,红帽将重点移向了中间件的应用(收购JBOSS)。Alan Cox是最早的一批Linux开发元老,是他解决了Linux的联网问题(Linux 0.11版本)。他在红帽工作了整整十年,做出了重大贡献。但是,他的才能集中表现在Linux底层的开发。他加盟Intel,意义非常重大。对于Linux而言,这意味着一个新时代的开始(by Glyn Moody)。
当前,Intel的Moblin计划正在紧张进行之中,必须赶在Windows 7发布之前,拿出成果,如同上甘岭(抗美援朝)争夺战。有了Alan Cox,Moblin计划更有希望,微软算是倒了霉。我们为Intel加油!
我们问,一般而言,在当今条件下,改造Linux桌面的“切入点”是什么?仅仅是界面美观、漂亮,不顶用。当今,用户在电脑上工作时,常常被飞来的即时信息所打扰,很分心,但是,又要及时得知有没有新的邮件待阅。总之,在线工作,带来了许多新问题。一个很典型的问题就是“自动通知”(notification)。现在的桌面“自动通知”,功能硬梆梆的,有事就打搅你,缺少人情味。Ubuntu抓住了这个“切入点”,12月22日,Ubuntu领头人Mark Shuttleworth发出战斗号召,要求彻底重建(overhaul)“自动通知”的功能体系,使Ubuntu 9.04新版本适应Moblin规范,拿出一个“不扰民”的Linux桌面发行版,迎战Windows 7。微软当然盯住Ubuntu的一举一动,但是,无奈“自动通知”不属于Windows 7本身的功能范围,只得干着急。我们试想,手中那着一个小小的MID(很小的计算机),触摸显示屏,浏览网页,同时,又有很人情味的“提醒”(即“自动通知”),绝不会耽误事情,心中该有多爽!小小的MID,里面凝聚多少人的聪明智慧,多少人的劳动汗水,但是,对于广大用户而言,一切都是“Free”(免费),这是可能的吗?答曰:完全可能。用户交给运营商的“月租费”,就是所谓“SaaS”模式的实现。将来,应用软件消失了,只剩下付费服务。当今,软件开发商要靠近网络运营商,与他们“分成”才是(似乎是唯一)出路。将来,我们玩MID时,不要忘记Alan Cox以及Intel的Moblin开发团队。事实上,Intel的Moblin成了现代Linux的急先锋。当前,人才会聚Intel,心向Moblin,2009年,Linux会战(Intel与Ubuntu)大有希望。
select支持非阻塞多客户访问
12 20, 2008 Linux
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct timeval tv;
char hello[]=”Hello!Are you kidding me?\n”;
char recv_buf[1024] = {0};
int sockfd, new_fd;
int sin_size, portnumber;
int i, j, maxi, nfds, temp_set[FD_SETSIZE];
int ready = -1;
fd_set read_fdset, write_fdset, allset;
new_fd = -1;
maxi = -1;
memset(temp_set, -1, FD_SETSIZE);
if (argc != 2)
{
fprintf(stderr, “Usage:%s portnumber\a\n”, argv[0]);
exit(1);
}
if ( (portnumber = atoi(argv[1])) < 0)
{
fprintf(stderr, “Usage:%s portnumber\a\n”, argv[0]);
exit(1);
}
/* Create socket descriptor */
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, “sock error:%s\n\a”, strerror(errno));
exit(1);
}
/* fill sockaddr structure */
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(portnumber);
/* bind */
if (bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr))==-1)
{
fprintf(stderr, “Bind error:%s\n\a”, strerror(errno));
exit(1);
}
/* listen */
if (listen(sockfd, FD_SETSIZE) == -1)
{
fprintf(stderr, “listen error:%s\n\a”, strerror(errno));
exit(1);
}
FD_ZERO(&allset);
FD_SET(sockfd, &allset);
nfds = sockfd + 1;
printf(”waiting for client connecting…listen file des: %d\n”, sockfd);
while (1)
{
tv.tv_sec = 1;
tv.tv_usec = 0;
read_fdset = allset;
ready = select(nfds, &read_fdset, NULL, NULL, &tv);
if ( ready < 0)
{
fprintf(stderr, “select error: %s\n”, strerror(errno));
break;
}
/*
else if (0 == ready)
{
printf(”not ready…\n”);
continue;
}
*/
/* server blocked, until client create connection */
sin_size = sizeof(struct sockaddr_in);
new_fd = -1; /* reset new_fd */
if (FD_ISSET(sockfd, &read_fdset) ) /* new connection */
{
if ( (new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size)) == -1)
{
fprintf(stderr, “Accept error:%s\n\a”, strerror(errno));
continue;
}
fprintf(stdout, “Server get connection from %s\n”, inet_ntoa(client_addr.sin_addr));
FD_SET(new_fd, &write_fdset); /* add to write_fdset for write */
FD_SET(new_fd, &allset); /* add to read_fdset for read */
for (i = 0; i < FD_SETSIZE; i++)
{
if (temp_set[i] < 0)
{
temp_set[i] = new_fd;
break;
}
}
if (i == FD_SETSIZE)
printf(”too many connections…\n”);
if (i > maxi)
maxi = i;
if (nfds < (new_fd+1) )
nfds = new_fd + 1;
/*
* send data to every client
*/
if (write(new_fd, hello, strlen(hello) ) == -1)
{
fprintf(stderr, “Write Error:%s\n”, strerror(errno));
exit(1);
}
//sleep(5);
//FD_CLR(new_fd, &write_fdset);
}
else
{
for (j = 0; j <= maxi; ++j)
{
if (temp_set[j] < 0)
continue;
if (FD_ISSET(temp_set[j], &read_fdset) ) /* any data to read? */
{
bzero(recv_buf, sizeof(recv_buf)); /* reset recv buffer */
fprintf(stdout, “it is the %d file reading\n”, temp_set[j]);
if (read(temp_set[j], recv_buf, 1024) > 0)
{
fprintf(stdout, “Server recv:(%s)\n”, recv_buf);
write(”Kobe Bryant, welcome to Beijing City!\n”);
}
else
{
fprintf(stderr, “Disconnect by client…\n”);
FD_CLR(temp_set[j], &allset);
close(temp_set[j]);
temp_set[j] = -1;
}
}
}
}
}
close(sockfd);
exit(0);
}
简易计算器
11 14, 2008 Linux
随便写的一个计算算术表达式的程序,支持正数,+,-,*/,()运算符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Maxsize 81
/* 运算符栈 */
struct stack_oper
{
char oper[Maxsize];
int top;
}operstack;
/* 数据栈 */
struct stack_data
{
float data[Maxsize];
int top;
}datastack;
char pop_stack_oper(struct stack_oper *p_operstack)
{
char temp;
if (p_operstack->top >= 0)
{
temp = (p_operstack -> oper)[p_operstack->top];
}
else
{
fprintf(stderr, “Operator stack is empty…\n”);
return ‘+’; /* 如果运算符栈为空,默认返回’+’ */
}
–(p_operstack->top);
return temp;
}
void push_stack_oper(struct stack_oper *p_operstack, char oper)
{
++(p_operstack->top);
(p_operstack -> oper)[p_operstack->top] = oper;
}
float pop_stack_data(struct stack_data *p_datastack)
{
float temp;
if (p_datastack->top >= 0)
{
temp = (p_datastack -> data)[p_datastack->top];
}
else
{
fprintf(stderr, “Data stack is empty…\n”);
return 0.0; /* 如果数据栈为空,默认返回0.0 */
}
–(p_datastack->top);
return temp;
}
void push_stack_data(struct stack_data *p_datastack, float data)
{
++(p_datastack->top);
(p_datastack -> data)[p_datastack->top] = data;
}
float cal_part(float data[], char oper[], int data_index, int oper_index)
{
float result = 0.0;
int i, j, m, n;
i = data_index-1;
j = oper_index-1;
//result = data[i];
/* debug */
/*
{
int t1;
for (t1=0; t1<data_index; ++t1)
printf(”%.2f “, data[t1]);
printf(”\n”);
}
*/
/* 先处理’*'跟’/',因为优先级更高 */
–i;
for ( ; j >= 0; –j)
{
switch (oper[j])
{
case ‘*’:
data[i+1] = data[i+1] * data[i];
for (m = i + 1; m < data_index; ++m) /* 左移后面那段数据 */
{
data[m-1] = data[m];
}
–data_index;
for (n = j + 1; n < oper_index; ++n) /* 左移后面那些操作符 */
{
oper[n-1] = oper[n];
}
–oper_index;
break;
case ‘/’:
if (data[i] != 0.0)
{
data[i+1] = data[i+1] / data[i];
}
else
{
fprintf(stderr, “Devide 0…program quit!\n”);
exit(1);
}
for (m = i + 1; m < data_index; ++m) /* 左移后面那段数据 */
{
data[m-1] = data[m];
}
–data_index;
for (n = j + 1; n < oper_index; ++n) /* 左移后面那些操作符 */
{
oper[n-1] = oper[n];
}
–oper_index;
break;
default:
break;
}
–i;
}
i = data_index-1;
j = oper_index-1;
/* 再处理’+'跟’-’ */
result = data[i];
–i;
for ( ; j >= 0; –j)
{
switch (oper[j])
{
case ‘+’:
result += data[i];
break;
case ‘-’:
result -= data[i];
break;
default:
break;
}
–i;
}
return result;
}
float compvalue(char exp[])
{
char part_oper[20] = {0}; /* 存放运算符数组 */
float part_data[21] = {0.0};/* 存放浮点数数组 */
char p_data[16] = {0}; /* 存放浮点数字符串 */
char *p_exp = NULL; /* 指向表达式某个字符 */
float data = 0.0; /* 存放转换后的浮点数 */
float part_result = 0.0; /* 存放结果值 */
int sdata_index = 0; /* 浮点数字符串指示器 */
int oper_index = 0; /* 运算符数组指示器 */
int data_index = 0; /* 浮点数组指示器 */
char temp = 0; /* 临时存放出栈字符 */
p_exp = exp;
while (*p_exp != 0)
{
switch (*p_exp)
{
case ‘ ‘: /* 如果是空格,什么都不做 */
break;
case ‘(’:
push_stack_oper(&operstack, *p_exp);
break;
case ‘*’:
push_stack_oper(&operstack, *p_exp);
break;
case ‘+’:
push_stack_oper(&operstack, *p_exp);
break;
case ‘-’:
push_stack_oper(&operstack, *p_exp);
break;
case ‘/’:
push_stack_oper(&operstack, *p_exp);
break;
case ‘)’: /* 此时计算该括号内的表达式的值 */
part_data[data_index] = pop_stack_data(&datastack);
++data_index;
//temp = pop_stack_oper(&operstack);
while ( (temp=pop_stack_oper(&operstack)) != ‘(’)
{
part_oper[oper_index] = temp;
++oper_index;
part_data[data_index] = pop_stack_data(&datastack);
++data_index;
}
part_result = cal_part(part_data, part_oper, data_index, oper_index);
//printf(”part result:%.2f\n”, part_result); /* debug */
push_stack_data(&datastack, part_result);
/* reset */
memset(part_oper, 0, sizeof(part_oper));
memset(part_data, 0, sizeof(part_data));
data_index = 0;
oper_index = 0;
part_result = 0.0;
/* debug */
/*
{
int h;
for (h = 0; h <= datastack.top; ++h)
printf(”%.2f “, datastack.data[h]);
printf(”\n”);
for (h = 0; h <= operstack.top; ++h)
printf(”%c “, operstack.oper[h]);
printf(”\n”);
}
*/
break;
default:
p_data[sdata_index] = *p_exp;
if ( (*(p_exp+1) == ‘(’) || (*(p_exp+1) == ‘*’) || (*(p_exp+1) == ‘+’) ||
(*(p_exp+1) == ‘-’) || (*(p_exp+1) == ‘/’) || (*(p_exp+1) == ‘)’) ||
(*(p_exp+1) == 0) )
{
p_data[sdata_index+1] = 0;
data = atof(p_data); /* 把字符串转换成浮点类型 */
push_stack_data(&datastack, data); /* 该浮点数进栈 */
memset(p_data, 0, sizeof(p_data)); /* reset */
sdata_index = 0; /* reset */
}
else
++sdata_index;
break;
}
++p_exp; /* 字符指针后移,助于遍历 */
}
/* 先判断栈是否为空 */
if (operstack.top < 0) /* 运算符栈为空说明运算完毕,只要弹出数据栈中的数据(也就是结果) */
{
return pop_stack_data(&datastack);
}
else /* 计算 */
{
/*
* 所有数据跟运算符出栈
*/
part_data[data_index] = pop_stack_data(&datastack);
++data_index;
while ( operstack.top >= 0) /* 保证所有的运算符都出栈 */
{
part_oper[oper_index] = pop_stack_oper(&operstack);
++oper_index;
part_data[data_index] = pop_stack_data(&datastack);
++data_index;
}
return cal_part(part_data, part_oper, data_index, oper_index);
}
}
int main(void)
{
char exp[81] = {0};
memset(&operstack, 0, sizeof(operstack));
memset(&datastack, 0, sizeof(datastack));
operstack.top = -1;
datastack.top = -1;
printf(”请输入算术表达式:\n”);
scanf(”%s”, exp);
exp[strlen(exp)] = 0;
printf(”%s计算结果:%.2f\n”, exp, compvalue(exp) );
return 0;
}
函数指针浅谈
11 14, 2008 Linux
函数存放在内存的代码区域内,它们同样有地址。如果我们有一个int test(int a)的函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。
定义一个指向函数的指针用如下的形式,以上面的test()为例: int (*fp)(int a);//这里就定义了一个指向函数的指针
函数指针不能绝对不能指向不同类型,或者是带不同形参的函数,在定义函数指针的时候我们很容易犯如下的错误。int *fp(int a);//这里是错误的,因为按照结合性和优先级来看就是先和()结合,然后变成了一个返回整形指针的函数了,而不是函数指针,这一点尤其需要注意!
#include <stdio.h>
#include <stdlib.h>
typedef int (*FUNCTION)(int);
int f1(int k)
{
return k;
}
int f2(int j)
{
return j;
}
int f3(int i)
{
return i;
}
int (*foo1(void))[]
{
static int sdata[] = {1, 2, 3};
return sdata;
}
FUNCTION (*foo2(void))[]
{
static FUNCTION sfunc[] = {f1, f2, f3};
return sfunc;
}
int main(void)
{
FUNCTION *pfunc = foo2();
int *p = foo1();
int i = 0;
for ( ; i < 3; ++i)
printf(”%d\n”, p[i]);
for (i=0; i<3; ++i)
printf(”%d\n”, pfunc[i](100));
return 0;
}
利用typedef定义可以简化函数指针的定义,上述示例中typedef int (*FUNCTION)(int);,如果不用这个定义,则需要这样写:int (*((*foo3(void))(int)))[],这样看起来比较吃力。
指针数组元素所保存的只是一个内存地址,既然只是个内存地址就不可能进行a[0]()这样地址带括号的操作,而函数指针不同它是一个例外,函数指针只所以这么叫它就是因为它是指向函数指向内存的代码区的指针,它被系统授予允许与()括号操作的权利,进行间接的函数调用,既然函数指针允许这么操作,那么被定义成函数指针的数组就一定是可以一样的操作的。
gcc编译选项介绍(转)
11 6, 2008 Linux
gcc编译选项介绍(转)
[介绍]
gcc and g++分别是gnu的c & c++编译器
gcc/g++在执行编译工作的时候,总共需要4步
1.预处理,生成.i的文件[预处理器cpp]
2.将预处理后的文件不转换成汇编语言,生成文件.s[编译器egcs]
3.有汇编变为目标代码(机器代码)生成.o的文件[汇编器as]
4.连接目标代码,生成可执行程序[链接器ld]
[参数详解]
-x language filename
设定文件所使用的语言,使后缀名无效,对以后的多个有效.也就是根据约定C语言的后 缀名称是.c的,而
C++的后缀名是.C或者.cpp,如果你很个性,决定你的C代码文件的后缀 名是.pig 哈哈,那你就要用这个
参数,这个参数对他后面的文件名都起作用,除非到了 下一个参数的使用。
可以使用的参数吗有下面的这些 `c’, `objective-c’, `c-header’, `c++’, `cpp-output’,
`assembler’, and `a ssembler-with-cpp’. 看到英文,应该可以理解的。
例子用法: gcc -x c hello.pig
-x none filename 关掉上一个选项,也就是让gcc根据文件名后缀,自动识别文件类型
例子用法: gcc -x c hello.pig -x none hello2.c
-c 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
例子用法: gcc -c hello.c 他将生成.o的obj文件
-S 只激活预处理和编译,就是指把文件编译成为汇编代码。
例子用法 gcc -S hello.c 他将生成.s的汇编代码,你可以用文本编辑器察看
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面.
例子用法: gcc -E hello.c > pianoapan.txt gcc -E hello.c | more 慢慢看吧,一个
hello word 也要与处理成800行的代码
-o 制定目标名称,缺省的时候,gcc 编译出来的文件是a.out,很难听,如果你和我有同感 ,改掉它,哈
哈
例子用法
gcc -o hello.exe hello.c (哦,windows用习惯了)
gcc -o hello.asm -S hello.c -pipe 使用管道代替编译中临时文件,在使用非gnu汇编工具的时候,
可能有些问题
gcc -pipe -o hello.exe hello.c -ansi 关闭gnu c中与ansi c不兼容的特性,激活ansi c的专有特
性(包括禁止一些asm inl ine typeof关键字,以及UNIX,vax等预处理宏,
-fno-asm 此选项实现ansi选项的功能的一部分,它禁止将asm,inline和typeof用作关键字。
-fno-strict-prototype 只对g++起作用,使用这个选项,g++将对不带参数的函数,都认为是没有显式
的对参数 的个数和类型说明,而不是没有参数. 而gcc无论是否使用这个参数,都将对没有带参数的函数,
认为城没有显式说明的类型
-fthis-is-varialble 就是向传统c++看齐,可以使用this当一般变量使用.
-fcond-mismatch 允许条件表达式的第二和第三参数类型不匹配,表达式的值将为void类型
-funsigned-char -fno-signed-char -fsigned-char -fno-unsigned-char
这四个参数是对char类型进行设置,决定将char类型设置成unsigned char(前两个参 数)或者 signed
char(后两个参数)
-include file 包含某个代码,简单来说,就是便以某个文件,需要另一个文件的时候,就可以用它设
定,功能就相当于在代码中使用#i nclude 例子用法: gcc hello.c -include /root/pianopan.h
-imacros file 将file文件的宏,扩展到gcc/g++的输入文件,宏定义本身并不出现在输入文件中
-Dmacro 相当于C语言中的#define macro
-Dmacro=defn 相当于C语言中的#define macro=defn
-Umacro 相当于C语言中的#undef macro -undef 取消对任何非标准宏的定义
-Idir 在你是用#i nclude”file”的时候,gcc/g++会先在当前目录查找你所制定的头文件,如 果没有找
到,他回到缺省的头文件目录找,如果使用-I制定了目录,他回先在你所制定的目录查找,然后再按常规的顺
序去找. 对于#i nclude,gcc/g++会到-I制定的目录查找,查找不到,然后将到系统的缺 省的头文件目录查
找
-I- 就是取消前一个参数的功能,所以一般在-Idir之后使用
-idirafter dir 在-I的目录里面查找失败,讲到这个目录里面查找.
-iprefix prefix -iwithprefix dir 一般一起使用,当-I的目录查找失败,会到prefix+dir下查找
-nostdinc 使编译器不再系统缺省的头文件目录里面找头文件,一般和-I联合使用,明确限定头 文件的位
置
-nostdin C++ 规定不在g++指定的标准路经中搜索,但仍在其他路径中搜索,.此选项在创libg++库 使用
-C 在预处理的时候,不删除注释信息,一般和-E使用,有时候分析程序,用这个很方便的
-M 生成文件关联的信息。包含目标文件所依赖的所有源代码你可以用gcc -M hello.c 来测试一下,很
简单。
-MM 和上面的那个一样,但是它将忽略由#i nclude造成的依赖关系。
-MD 和-M相同,但是输出将导入到.d的文件里面
-MMD 和-MM相同,但是输出将导入到.d的文件里面
-Wa,option 此选项传递option给汇编程序;如果option中间有逗号,就将option分成多个选项,然 后传
递给会汇编程序
-Wl.option 此选项传递option给连接程序;如果option中间有逗号,就将option分成多个选项,然 后
传递给会连接程序.
-llibrary 制定编译的时候使用的库 例子用法 gcc -lcurses hello.c 使用ncurses库编
译程序
-Ldir 制定编译的时候,搜索库的路径。比如你自己的库,可以用它制定目录,不然 编译器将只在
标准库的目录找。这个dir就是目录的名称。
-O0 -O1 -O2 -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-g 只是编译器,在编译的时候,产生调试信息。
-gstabs 此选项以stabs格式声称调试信息,但是不包括gdb调试信息.
-gstabs+ 此选项以stabs格式声称调试信息,并且包含仅供gdb使用的额外调试信息.
-ggdb 此选项将尽可能的生成gdb的可以使用的调试信息.
-static 此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么 动态连接库
,就可以运行.
-share 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
-traditional 试图让编译器支持传统的C语言特性


