搜索
查看: 8362|回复: 29
打印 上一主题 下一主题

谣言终结(伪):使用Sleep就一定要添加windows.h吗?

[复制链接]
跳转到指定楼层
楼主
发表于 2013-6-21 00:48:42 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
本帖最后由 rosynirvana 于 2013-6-21 00:53 编辑

这是从啊哈C十万个为什么中挑选出来的问题,实用性比前面一篇好多了。

和上一篇一样,刚入门的站友,看第一部分就好了。

下面的代码在ahaC 2.0中明显是无法编译的
  1. #include <stdio.h>

  2. int main()
  3. {
  4.         puts("Hello World!");
  5.         sleep(1);
  6.         return 0;
  7. }
复制代码
论坛上对于这个问题最常见的回答是
sleep首字母大写,并且加一句#include <windows.h>

这当然是可行的,但是有没有考虑过,为什么会导致无法编译呢?

下面先说一种最为直接(也是最正确的)的解决方法
  1. #include <stdio.h>
  2. void __stdcall Sleep(unsigned long);

  3. int main()
  4. {
  5.         puts("Hello World!");
  6.         Sleep(1);
  7.         return 0;
  8. }
复制代码
Sleep首字母大写是当然的,C语言对于大小写敏感——sleep和Sleep是两个不同的函数。但是只做这个改动还是无法编译——所以另外加了一句
  1. void __stdcall Sleep(unsigned long);
复制代码
这个看上去非常奇怪的东西。

其实,这只是一个函数原型。但不是标准C的函数原型,在ISO C中,没有__stdcall这种东西。
__stdcall事实上是一种calling convention,决定生成函数调用的汇编代码的一些细节问题。

为了让这段代码运行起来,最重要的就是这个__stdcall了,你可以试试把这句替换成下面几句中的一句:
  1. __stdcall Sleep(int);
  2. void __stdcall Sleep(int);
  3. __stdcall Sleep(float);
复制代码
都是可以运行的(但是你可能发现第3句暂停时间非常长)

为什么要加了这个calling convention才能正常编译呢?因为它会影响汇编代码的生成。
如果没有这句声明函数原型,汇编代码是
  1. call        _Sleep
复制代码
如果加上这句声明,汇编代码是
  1. call        _Sleep@4
复制代码
你可能已经明白了,函数在运行库内部的名字是不同的,所以不声明函数原型的情况下,会造成一个链接期的错误。

_Sleep@4这个符号,在链接期会被解析到libkernel32.a中,然后再进行符号重定位,运行时调用kernel32.dll中相应的二进制代码。

最后需要说明的是,为什么#include <windows.h>也能解决这个问题呢?
因为windows.h会将Sleep的原型声明拷贝到你的源码文件中去,Sleep这个函数最为正规的原型是
void WINAPI Sleep(DWORD);
其中WINAPI和DWORD是宏,在mingw预处理的时候分别被替换成 __stdcall 和unsigned long:
void __stdcall Sleep(unsigned long);
也就是本文一开始添加的那句声明。

评分

参与人数 3啊哈币 +11 收起 理由
code004 + 3 很给力!
创世菌 + 3 很给力!
啊哈磊 + 5 赞一个!

查看全部评分

推荐
发表于 2013-10-14 11:01:49 | 只看该作者
霁涟熙 发表于 2013-6-21 09:12
膜拜。另外小白的问一下,是不是一定要大写S能,有没有办法用sleep也可以呢?

_sleep.......
推荐
 楼主| 发表于 2013-10-5 20:22:19 | 只看该作者
wkl 发表于 2013-10-5 16:59
mingw中应该没有windows.h这个库吧,为什么加上include 这个库后,就可以
你说    “因为windows.h会将Sle ...

windows.h不是一个库啊,只是一个头文件而已
通常的mingw安装包包含了一个叫win32api的部分,这个部分里面包含了windows.h这个头文件
所以说windows.h可以说是mingw的一个可选组件
啊哈C只是mingw的一个图形前端而已

我想应该解释清除了吧
推荐
发表于 2013-10-5 16:59:49 | 只看该作者
mingw中应该没有windows.h这个库吧,为什么加上include <windows.h>这个库后,就可以
你说    “因为windows.h会将Sleep的原型声明拷贝到你的源码文件中去”

这个windows.h是啊哈C自带的(而不是mingw自带)的吗?
谢谢!
推荐
 楼主| 发表于 2013-8-28 13:23:24 | 只看该作者
Cousin 发表于 2013-8-27 21:35
你让unistd.h情何以堪

啊哈C又不能运行在unix环境上
请先搞清楚哪些是标准库
28#
 楼主| 发表于 2014-9-28 04:11:45 | 只看该作者
Abe_Ho 发表于 2014-6-4 20:41
那为什么书上 可以运行呢

因为很早之前的mingw提供sleep,后来没了
27#
发表于 2014-6-4 20:41:15 | 只看该作者
那为什么书上 可以运行呢

捕获.PNG (55.02 KB, 下载次数: 5)

图片

图片
26#
发表于 2014-3-9 00:20:07 | 只看该作者
唉。看来我的知识还不足啊。郁闷。这些内容好像很深奥
25#
发表于 2014-3-8 17:38:50 | 只看该作者
rosynirvana 发表于 2014-3-2 21:36
如果想真正理解这个问题,C的编译、链接这些知识是不必可少的
如果你看不懂,那么说明你的知识储备不足 ...

原来是这样,我懂了。
24#
 楼主| 发表于 2014-3-2 21:36:41 | 只看该作者
1233333 发表于 2014-3-2 19:26
为什么我一点都看不懂,楼主,请用你啊哈磊的模式教教我吧!

如果想真正理解这个问题,C的编译、链接这些知识是不必可少的
如果你看不懂,那么说明你的知识储备不足,也就是说明还没到去理解这个问题的阶段
23#
发表于 2014-3-2 19:26:26 | 只看该作者
为什么我一点都看不懂,楼主,请用你啊哈磊的模式教教我吧!
22#
发表于 2014-2-23 23:52:06 | 只看该作者
妈妈叫我去打酱油了。。。
21#
发表于 2014-1-8 21:46:34 | 只看该作者
大神膜拜一下。楼主是啊哈论坛第一大神~

点评

磊大大不算吧。。。  发表于 2014-1-8 21:46
20#
发表于 2013-12-9 13:03:50 | 只看该作者
本帖最后由 stu 于 2013-12-9 13:23 编辑
rosynirvana 发表于 2013-12-9 12:54
和第四章最后一道一样,只打印两端的*,中间换成空格
自己试着写写,问别人要代码对你帮助不大

知道了 书昨天发货了还没到呢 目前看的是PDF的  此问题已搞定{:soso_e115:}
19#
 楼主| 发表于 2013-12-9 12:54:54 | 只看该作者
stu 发表于 2013-12-9 12:18
那个我下载看过了  我想知道怎么利用FOR语句循环实现菱形

#include

和第四章最后一道一样,只打印两端的*,中间换成空格
自己试着写写,问别人要代码对你帮助不大
18#
发表于 2013-12-9 12:18:24 | 只看该作者
本帖最后由 stu 于 2013-12-9 12:33 编辑
rosynirvana 发表于 2013-12-9 11:24
因为Sleep是WINAPI
你写的所有东西在windows上都要转成winapi,printf也好scanf也好system也好

那个我下载看过了  我想知道怎么利用FOR语句循环实现菱形

#include <math.h>

void main()
{
int i, j, k;
for (i = -3; i <= 3; i++)
{
k = abs(i);
for (j = 1; j <= k; j++)
printf(" ");
for (j = 1; j <= 7 - 2 * k; j++)
printf("*");
printf("\n");
}
system("color b5");
system("pause");
}


实现的菱形和电子PDF里的还是不一样 http://bbs.ahalei.com/thread-3875-1-1.html
17#
 楼主| 发表于 2013-12-9 11:24:51 | 只看该作者
stu 发表于 2013-12-9 11:16
哦 原来是这么玩的   另外自己写个sleep函数 其实质还是调用Sleep  刚学 好多看的有点晕 怎么只有4以后的 ...

因为Sleep是WINAPI
你写的所有东西在windows上都要转成winapi,printf也好scanf也好system也好

前四章是很久之前写的,在另一个帖子里
http://bbs.ahalei.com/thread-1340-1-2.html
16#
发表于 2013-12-9 11:16:10 | 只看该作者
rosynirvana 发表于 2013-10-5 20:22
windows.h不是一个库啊,只是一个头文件而已
通常的mingw安装包包含了一个叫win32api的部分,这个部分里 ...

哦 原来是这么玩的   另外自己写个sleep函数 其实质还是调用Sleep  刚学 好多看的有点晕 怎么只有4以后的习题答案  习题一怎没的 谢谢
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

广播台
特别关注
快速回复 返回顶部 返回列表