由System V消息队列引发的思考
最近看unp的卷2,自己写了一下书上的例子。因为作者是直接包含他自己写的头文件而书中并没有列出来,所以只能自己man函数而得到相应的头文件。那么问题来了,
struct msgbuf{
long mtype;
char mtext[1];
}
书上说这个结构体包含在<sys/msg.h>中,但恰恰就是在这个结构体出了问题。还是先上源代码。
第一版的编译是错误的源代码:
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<stdlib.h>
typedef unsigned long ulong_t;
int main()
{
int msqid;
struct msqid_ds info;
struct msgbuf buf;
int oflag=0664|IPC_CREAT;
if((msqid=msgget(IPC_PRIVATE,oflag))<0)
perror("msgget error");
buf.mtype=1;
buf.mtext[0]=1;
if(msgsnd(msqid,&buf,1,0)<0)
perror("msgsnd error");
if(msgctl(msqid,IPC_STAT,&info)<0)
perror("msgctl error");
printf("read-write:%03o,cbytes=%lu,qnum=%lu,qbytes=%lu\n",info.msg_perm.mode&0777,(ulong_t)info.msg_cbytes,(ulong_t)info.msg_qnum,
(ulong_t)info.msg_qbytes);
system("ipcs -q");
if(msgctl(msqid,IPC_RMID,NULL))
perror("msgctl error");
exit(0);
}
编译后显示如下:
明明我包含了头文件<sys/msg.h>而书上说了该结构体在该文件中定义了,难道书上写错了
下面用sed命令来看一下<sys/msg.h>头文件中关于msgbuf结构体:
由上图可知,msgbuf显然是在头文件中定义了的。但是,当你仔细看时就会发现在结构体上面的一句#ifdef __USE_GNU也就是说要定义了__USE_GNU了后才会声明msgbuf结构体
但是当我定义了__USE_GNU了后就还是同样的错误。Google了一下,上面是这样说的
This is wrong, __USE_GNU is glibc internal macro that shouldn't be ever
defined by apps.
The way to select GNU feature set in glibc headers is to define _GNU_SOURCE,
either before including first include header in the source .c/.C file,
or by defining it on the command line (-D_GNU_SOURCE).
也就是说要定义__GNU_SOURCE或者在编译的时候加上-D _GNU_SOURCE
注意#define __GNU_SOURCE要写在头文件之前
关于_GNU_SOURCE宏,发现它是在features.h中用于特性控制的一个功能测试宏
</user/include/features.h>
/* If _GNU_SOURCE was defined by the user, turn on all the other features. */
#ifdef _GNU_SOURCE
# undef _ISOC99_SOURCE
# define _ISOC99_SOURCE 1
# undef _POSIX_SOURCE
# define _POSIX_SOURCE 1
# undef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 200809L
# undef _XOPEN_SOURCE
# define _XOPEN_SOURCE 700
# undef _XOPEN_SOURCE_EXTENDED
# define _XOPEN_SOURCE_EXTENDED 1
# undef _LARGEFILE64_SOURCE
# define _LARGEFILE64_SOURCE 1
# undef _BSD_SOURCE
# define _BSD_SOURCE 1
# undef _SVID_SOURCE
# define _SVID_SOURCE 1
# undef _ATFILE_SOURCE
# define _ATFILE_SOURCE 1
#endif
其中_ISOC99_SOURCE, _POSIX_SOURCE, _XOPEN_SOURCE都是功能测试宏,用于指示是否包含对应标准的特性,而这些不同的特性源于过去20多年来进行的各种标准化工作(ANSI, ISO, POSIX, FIPS等),不同的标准支持实现了不同的特性,如系统时间的获取,stat结构是在ANSI标准中是不支持的,而定义了_GNU_SOURCE相当于开启了对所有特性的支持。
关于功能测试宏可以man feature_test_macros
其中有几个功能测试宏是被默认定义的,如图
说明即使自己没定义功能测试宏,也会有一下功能测试宏被默认定义了
另外有几个man page 也有必要看一下
man libc
man syscalls
man standards