APUE习题2.3 —— sysconf 的使用和调整

守护进程在运行后常做的一件事情是关闭当前所有打开的文件。代码如:

#include 

for (i = 0; i

我们希望使用POSIX.1的OPEN_MAX来提高代码可移植性, (OPEN_MAX 表示系统设置的能打开的最大文件数)

#include 

for (i = 0; i

但是有可能会出现系统未设置OPEN_MAX值的情况,sysconf会返回-1导致for循环根本不会运行,这里编写小程序。
PS: 根据书后习题,添加了当OPEN_MAX被系统缺省设置为LONG_MAX的情况,如果是那样的话,会浪费大量时间。

/* *
 *
 *	CHANGE CODE 2-4 IN APUE ACC FOR LONG_MAX RETURN BY SYSCONF
 *
 *	APUE TEST 2.3
 *
 *	MIUC 2011.06.26
 *
 * */

#include 
#include 
#include 
#include 

#ifdef OPEN_MAX
static long openmax = OPEN_MAX;
#else
static long openmax = 0;
#endif

#define OPEN_MAX_GUESS 256

long open_max(void)
{
	if (openmax == 0) {
		errno = 0;
		if ((openmax = sysconf(_SC_OPEN_MAX)) < 0) {
			if (errno == 0) 
				openmax = OPEN_MAX_GUESS;	/* it's indeterminate */
			else {
				printf("sysconf error for _SC_OPEN_MAX\n");
				return -1;
			}
		} else 
		if (openmax == LONG_MAX) openmax = OPEN_MAX_GUESS; /* LONG_MAX is too long , waste time */
	}
	return openmax;
}

int main()
{
	printf("openmax : %ld\n", open_max());
	return 0;
}

发表在 C, Linux, 系统, 编程 | 标签为 , , , | 留下评论

此文章使用ScribeFire发布!

 ScribeFire是Firefox下的一款插件,用于博客文章的编写和发布。
 拥有自动上传图片的功能,在Linux使用比较方便。

 

发表在 博客 | 标签为 , | 留下评论

关于const pointer 的测试

睡前无聊看了下APUE的习题,测试下const pointer,详细信息看注释

#include 


int main()
{
	int a = 3;
	const int * b = &a;

	//	*b++;  compile access, run like *(b++)
	//	(*b)++ compile error ,  *b can not edit

	printf("%d\n", a);


	int c = 3;
	// int const * d = &c;  compile access, 'int const' like 'const int'

	int * const d = &c; 	

	//*d++;   //  compile error, d can't change

	printf("%d\n", c);


	int e[2] = {3, 4};

	const int * f = e;

	// f[0]++;   error, *f can not change
	
	// f[1]++;   error, *(f + 4u) can not change


	return 0;

}



发表在 C, 编程 | 标签为 , | 留下评论

【Gnome3 Extention weather】Gnome3 天气插件错误修正

今天闲来装上Gnome3的天气插件,遇到一些问题,这里简单写一些。
gnome-shell-extension-weather

1. 编译安装时遇到 Makefile 提示缺少符号,仔细查看config时候的输出,发现一个Error,安装Glib2-dev后正常
2. 安装插件后,可以在 /usr/share/gnome-shell/extension/下找到,或者在 ~/.local/share/. ooxxx 下面
3. 发现插件显示和yahoo正确的气温不符,仔细看了下js代码,找到GET 的url,发现yahoo 那边传过来的今天详细天气数据都错了。
4. 测试了下语法可行性,因为第二次调用forecast返回的今明天气是正确的,可以临时做以下操作:
A. 交换 刷新今日详细信息 和 刷新今明天气信息 的函数。
B. 在今明天气信息里做判断,预先填充部分今天天气信息。
C. 在今日详细里注释掉重复部分。

ctr+F2 r 重启gnome3 OK

发表在 Linux, 系统 | 标签为 , , | 2条评论

[ZZ]清华博士王垠的退学申请

         从此我感觉到了什么叫做研究。这跟我小时候干的那些事情没有什么两样。你在身边发现一个 问题,想知道为什么。然后你就想去获得解决这个问题的知识。你去看书,你去问专家,你上网去搜索。如果没有发现答案,那么好啦,你就可以自己试图去发现为什么,这是最有趣的部分。知道了为什么,就想让这个东西有用处,对人们的生活产生好处。这就是研究。

                                                                                                                —— 文摘

经过深思熟虑,我决定放弃清华大学的博士学位。其中的原因,你们有兴趣的话可以看看下面的文章。这就是我的一生与中国教育的故事。一个用血和泪换来的教训。

清华梦的粉碎—写给清华大学的退学申请 2005.9.22

继续阅读

发表在 网摘, 网络 | 标签为 , | 留下评论

Eclipse下使用 Winpcap

1. 下载Winpcap开发包,在主页选择 Winpcap –> Dev…

2. 解压,方法一,对应文件直接复制到Eclipse使用的GCC编译器文件夹下,如MinGW\include\.. Lib文件同理

                 方法二,在Eclipse的编译选项里添加-i include.

3. 查看官方文档,在开发包的Doc里有,选择 Using WinPcap in your programs 查看文档信息。

4. 文档提示要添加preprocessor definitions,Project –> Pro… –> C/C++ Build –>Setting –> GCC C compiler –>symbols , 添加 WPCAP HAVE_REMOTE

5. 复制官方的第一个实例,编译运行。

 

—-  MinGW 下 Winpcap编译不通过的问题解释 —-

You can replace your localtime_s call with:

localtime_r(&local_tv_sec, &ltime);

(Note the swapped arguments.)

Also, replace your scanf_s call with scanf.

localtime_s() and scanf_s() are Microsoft-specific extensions, and are not available in MinGW

发表在 C, Eclipse, Windows, 系统, 编程 | 标签为 , | 留下评论

[推荐]Linux C编程一站式学习

虽然一直觉得”一站式”的称号有些过分,不过这篇文档作为 Linux操作手册 还是很好的。

《Linux下C编程入门》就是一片不错的PDF文档

发表在 Linux, 系统 | 标签为 | 留下评论

[转载]可变参数宏

作者:Gavin Shaw(综合整理) 更新日期:2006-08-22
来源:upsdn.net

在 GNU C 中,宏可以接受可变数目的参数,就象函数一样,例如:
#define pr_debug(fmt,arg…) \
printk(KERN_DEBUG fmt,##arg)
用可变参数宏(variadic macros)传递可变参数表
你可能很熟悉在函数中使用可变参数表,如:

void printf(const char* format, …);

直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中。

C99编译器标准终于改变了这种局面,它允许你可以定义可变参数宏(variadic macros),这样你就可以使用拥有可以变化的参数表的宏。可变参数宏就像下面这个样子:

#define debug(…) printf(__VA_ARGS__)

缺省号代表一个可以变化的参数表。使用保留名 __VA_ARGS__ 把参数传递给宏。当宏的调用展开时,实际的参数就传递给 printf()了。例如:

Debug(“Y = %d\n”, y);

而处理器会把宏的调用替换成:

printf(“Y = %d\n”, y);

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:

debug(“test”); //一个参数

可变参数宏不被ANSI/ISO C++ 所正式支持。因此,你应当检查你的编译器,看它是否支持这项技术。

用GCC和C99的可变参数宏, 更方便地打印调试信息

gcc的预处理提供的可变参数宏定义真是好用:

#ifdef DEBUG
#define dbgprint(format,args...) \
fprintf(stderr, format, ##args)
#else
#define dbgprint(format,args...)
#endif

如此定义之后,代码中就可以用dbgprint了,例如dbgprint("aaa %s", __FILE__);。感觉这个功能比较Cool  :em11:

下面是C99的方法:

#define dgbmsg(fmt,...) \
             printf(fmt,__VA_ARGS__)

新的C99规范支持了可变参数的宏

具体使用如下:

以下内容为程序代码:

#include <stdarg.h> #include <stdio.h>

#define LOGSTRINGS(fm, …) printf(fm,__VA_ARGS__)

int main() {      LOGSTRINGS("hello, %d ", 10);      return 0; }

但现在似乎只有gcc才支持。

可变参数的宏里的‘##’操作说明

带有可变参数的宏(Macros with a Variable Number of Arguments)

在1999年版本的ISO C 标准中,宏可以象函数一样,定义时可以带有可变参数。宏的语法和函数的语法类似。下面有个例子:

#define debug(format, …) fprintf (stderr, format, __VA_ARGS__)

这里,‘…’指可变参数。这类宏在被调用时,它(这里指‘…’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体(macro body)中,那些符号序列集合将代替里面的__VA_ARGS__标识符。更多的信息可以参考CPP手册。

GCC始终支持复杂的宏,它使用一种不同的语法从而可以使你可以给可变参数一个名字,如同其它参数一样。例如下面的例子:

#define debug(format, args…) fprintf (stderr, format, args)

这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

GNU CPP还有两种更复杂的宏扩展,支持上面两种格式的定义格式。

在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。例如,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

debug ("A message")

GNU CPP在这种情况下可以让你完全的忽略可变参数。在上面的例子中,编译器仍然会有问题(complain),因为宏展开后,里面的字符串后面会有个多余的逗号。

为了解决这个问题,CPP使用一个特殊的‘##’操作。书写格式为:

#define debug(format, …) fprintf (stderr, format, ## __VA_ARGS__)

这里,如果可变参数被忽略或为空,‘##’操作将使预处理器(preprocessor)去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。

怎样写参数个数可变的宏

一种流行的技巧是用一个单独的用括弧括起来的的 “参数" 定义和调用宏, 参数在 宏扩展的时候成为类似 printf() 那样的函数的整个参数列表。

    #define DEBUG(args) (printf("DEBUG: "), printf args)

if(n != 0) DEBUG(("n is %d\n", n));

明显的缺陷是调用者必须记住使用一对额外的括弧。

gcc 有一个扩展可以让函数式的宏接受可变个数的参数。 但这不是标准。另一种 可能的解决方案是根据参数个数使用多个宏 (DEBUG1, DEBUG2, 等等), 或者用 逗号玩个这样的花招:

    #define DEBUG(args) (printf("DEBUG: "), printf(args))
#define _ ,

DEBUG("i = %d" _ i);

C99 引入了对参数个数可变的函数式宏的正式支持。在宏 “原型" 的末尾加上符号 … (就像在参数可变的函数定义中), 宏定义中的伪宏 __VA_ARGS__ 就会在调用是 替换成可变参数。

最后, 你总是可以使用真实的函数, 接受明确定义的可变参数

如果你需要替换宏, 使用一个 函数和一个非函数式宏, 如 #define printf myprintf。

发表在 C, 编程 | 标签为 , | 留下评论

[转载]如何检测当前系统的 shell 版本

当 Unix/Linux 系统启动时,操作系统的内核部分被装入内存,其余部分仍在硬盘上,只有当用户请求执行时才会被加载到内存中。Unix/Linux 系统完成启动后,由内核中的 init 进程激活 getty 进程,getty 进程在相应的终端上显示“login: ”提示,等待用户登录。当用户输入用户名时,getty 进程读取用户输入并启动 login 进程,由 login 进程完成整个登陆过程。用户完成登录后,login 进程根据启动配置文件,启动与该登录用户相对应的“默认 shell ”。此时,shell 进程被启动,用户可以通过 shell 终端与系统内核进行交互。

各种各样的 shell

和 Unix/Linux 中的其它程序一样,shell 也仅仅是一个程序,在 Unix/Linux 系统中并没有特权。这也是为什么 Unix/Linux 系统中出现各种各样 shell 的原因。
1、Bourne shell(sh)。大多数 Unix 系统的默认安装 shell。
2、Korn shell(ksh)。
3、C shell(csh)。
4、TENEX/TOPS C shell(tcsh)。
5、Bourne Again shell(bash)。大多数 Linux 系统的默认安装 shell。

切换 shell

大多数的 Unix/Linux 系统都提供了多个 shell。当系统启动时,由启动配置文件确定启动(默认的) shell,用以用户与系统进行交互。
在 Red Hat 9 中,可以通过以下任何一种命令,确定登录用户的默认 shell。
cat /etc/passwd #M1
echo $SHELL #M2
在决定要切换 shell 之前,必须知道系统中安装了哪些 shell。在 Red Hat 9 中,可以通过以下命令,确定系统中已经安装的各种 shell 程序。
cat /etc/shells
在我的 Red Hat 9 系统中,得到了如下的结果:
/bin/sh
/bin/bash
/sbin/nologin
/bin/bash2
/bin/ash
/bin/bsh
/bin/tcsh
/bin/csh
可以看出来,这其实是一个 shell 程序文件的列表。一般来说,/bin 和 /sbin 目录都在环境变量 PATH 中。为了切换为我们喜欢的 shell 种类,(我们已经知道,shell 也仅仅是一种与系统进行交互的程序),我们只需要在命令提示符下输入 shell 在 /bin 和 /sbin 目录中的相应名称即可。

我在使用哪个 shell

Unix/Linux 系统极少被重新启动,多个对 shell 有不同爱好的管理员可能操纵过计算机,我们姑且假设他们都使用相同的管理帐号。于是,这就产生了一个问题,我的终端上究竟运行着什么样的 shell?
针对这个问题,我在 Google 上搜寻了一下,有各种各样的答案。有一个回答是
echo $SHELL
我觉得这是不对的,SHELL 是环境变量,在整个会话中都不回改变,它表示的是登录用户的“默认 shell ”。还有人说用
cat /etc/passwd
这样得到的结果也是登录用户的“默认 shell ”,很显然也不能解决上述问题。
在 Red Hat 9 系统上,我用下述方法解决这个问题:
首先,使用命令
echo $$
获得当前 shell 进程的 PID。我在测试中,得到的结果是 10650。
然后,使用命令
ps -A | grep 10650
获取进程列表,并进行筛选。得到这样的测试结果:
10650 pts/0 00:00:00 csh
于是得到的结论是,测试中使用的 shell 是 csh。

发表在 Linux, 系统 | 标签为 , | 留下评论

《上海堡垒》

你是凝结的时间,流动的语言, 
黑色的雾里,有隐约的光. 
可是透过你的双眼,会看不清世界, 
花朵的凋萎,在瞬间, 
而花朵的绽放,在昨天。

 

 

        有些事情,遇见了就不会忘记。  —— 2011 年 5 月 16 日

发表在 读书 | 标签为 , | 留下评论