打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
由stdout引发的思考
1 前言
今天早些时候在osc的技术问答模块发现一个有意思的问题http://www.oschina.net/question/1020892_114830,截图如下:
现将相关的分析思路整理成博文,和大家一起探讨下。
2 分析
以下是该问题的分析思路,如有错误之处,欢迎大家不吝指出,谢谢!
【1】man 3 stdout我们得到以下部分输出:
#include <stdio.h>       extern FILE *stdin;       extern FILE *stdout;       extern FILE *stderr;从上面我们可以看到stdout的类型是FILE *
【2】man 3 write我们得到以下部分输出:
#include <unistd.h>
ssize_t pwrite(int fildes, const void *buf, size_t nbyte,off_t offset);
ssize_t write(int fildes, const void *buf, size_t nbyte);从上面我们可以看到write(...)函数的头文件为unistd.h,且第一个参数的类型为int
【3】楼主帖子中的第一种方式
#include<stdio.h>int main(){
write(stdout,"hahhh",6);
return 0;}结合【1】中stdout的类型为FILE *以及【2】中的write(...)的第一个参数为int,所以在实际运行的时候,会将FILE *类型强制转换为int,而(int)stdout的结果为:-1122261984(不同的机器结果可能不一样)
write(stdout,"hahhh",6);等同于:
write(-1122261984,"hahhh",6);且我们知道STDOUT_FILENO为1,所以我们在屏幕上看不到任何的输出;
另外,如果我们加上-Wall参数进行编译,会得到如下的警告信息:
warning: passing argument 1 of ‘write’ makes integer from pointer without a cast [enabled by default]     write(stdout, "hahhh", 6);
这条警告的大致意思是write函数的第一个参数直接将指针赋值给整数;
【4】楼主帖子中的第二种方式:
#include<stdio.h>int main(){
write(1,"hahhh",6);
return 0;}当我们用gcc命令并加上-Wall编译后得到下面的警告信息:
warning: implicit declaration of function ‘write’ [-Wimplicit-function-declaration]    write(stdout, "hahhh", 6);    ^
出现这个警告的原因是从【2】我们看到write(...)的头文件是<unistd.h>,所以务必加上#include <unistd.h>
另外1为STDOUT_FILENO即标准输出,所以在屏幕上看到了我们所期望的输出。
Q:相信大家看到这里的时候,会发现一个问题,那就是为什么上面的代码中没有加<unistd.h>这个头文件,我们的程序依然可以运行,惟独只有编译的时候的跳出的一个警告信息。
我们先来了解一下基本的链接知识:
当gcc编译*.c文件的时候,如果发现某函数(如test())未定义或声明,编译器并未报错而只是提出警告,警告的信息一般如下:
warning: implicit declaration of function ‘test’ [-Wimplicit-function-declaration]编译器默认该函数会在其他的模块中定义,在链接阶段,如果还未找到该函数定义则报链接错误,一般错误信息如下:
undefined reference to `test' collect2: error: ld returned 1 exit status所以针对上面提出的问题,源程序中即使没有包含<unistd.h>头文件,同样可以编译通过。那为什么可以链接成功呢?
我们运行ldd a.out可以看到a.out依赖的动态链接库如下所示:
linux-vdso.so.1 =>  (0x00007fff1d7fe000)libc.so.6 => /lib64/libc.so.6 (0x00000034bce00000)/lib64/ld-linux-x86-64.so.2 (0x00000034bc600000)
从上面输出的结果,我们看到了大名鼎鼎的libc.so.6即libc动态链接库,我们从wikipedia中得到glic如下描述:
glibc provides the functionality required by the Single UNIX Specification, POSIX (1c, 1d, and 1j) and some of the functionality required by ISO C99, Berkeley Unix (BSD) interfaces, the System V Interface Definition (SVID) and the X/Open Portability Guide (XPG), Issue 4.2, with all extensions common to XSI (X/Open System Interface) compliant systems along with all X/Open UNIX extensions. In addition, glibc also provides extensions that have been deemed useful or necessary while developing GNU.另外我们得到unistd.h的相关描述如下:
In the C and C++ programming languages, unistd.h is the name of the header file that provides access to the POSIX operating system API.从上面的描述,我们可以看到glibc实现了single unix specificaton, POSIX等功能,且我们了解到unistd.h是POSIX API的头文件。
至此,我们得到libc中实现了<unistd.h>中定义的所有函数当然包括我们程序中用到的write(...)函数,所以链接过程不会出错,程序能够正常运行。
总结
从上述对帖子问题的分析,我们总结c语言编程的相关知识如下:
编译的时候加上-Wall参数,让编译器输出所有的警告信息,作为严谨的程序员,我们应该排除出现的所有的警告信息;
在编写程序的时候,务必加上正确的头文件,如不太清楚该函数属于哪个头文件,可借助linux下强大的man命令,另外还可以看到关于该函数的详细说明;
注1:
man 命令的不同section的具体含义如下:
SectionDescription
1General commands
2System calls
3Library functions, covering in particular the C standard library
4Special files (usually devices, those found in /dev) and drivers
5File formats and conventions
6Games and screensavers
7Miscellanea
8System administration commands and daemons
man 3为直接查看c标准库
注2:
unistd.h中的unistd表示unix standard方便大家记忆
如上述分析有错误之处,还望各位不吝指出,谢谢!
引用
[1] http://www.gnu.org/software/libc/
[2] http://en.wikipedia.org/wiki/GNU_C_Library
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux 下的 dup 和 dup2 函数简介
linux 下文件I/O编程 (open、read、write、lseek、close)
eCos启动流程解析
read,write和lseek函数
LinuxC.基本文件IO操作
同步内核缓冲区sync、fsync和fdatasync函数
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服