1 alloca(1)(harib25a)

今天我们准备来实现读取文件的功能和显示文字的功能,不过在做这些看上去很酷的事情之前,我们先来解决一些基本的问题,就当是热身吧。

首先,我们来编写一个简单的应用程序。

sosu.c

  1. #include <stdio.h>
  2. #include "apilib.h"
  3. #define MAX 1000
  4. void HariMain(void)
  5. {
  6. char flag[MAX], s[8];
  7. int i, j;
  8. for (i = 0; i < MAX; i++) {
  9. flag[i] = 0;
  10. }
  11. for (i = 2; i < MAX; i++) {
  12. if (flag[i] == 0) {
  13. /*没有标记的为质数*/
  14. sprintf(s, "%d ", i);
  15. api_putstr0(s);
  16. for (j = i * 2; j < MAX; j += i) {
  17. flag[j] = 1; /*给它的倍数做上标记*/
  18. }
  19. }
  20. }
  21. api_end();
  22. }

这个程序的功能是显示1000以内的质数,所谓质数,就是“只能被1及其本身整除的大于1的自然数”,例如2、3、5、7都是质数1,而4可以被2整除,6可以被2和3整除,因此它们不是质数。

1 质数又称素数。为什么这样的数会被称为素数呢?因为凡是2以上的整数都可以写成两个素数的乘积,也就是说,素数相当于构成整数世界的“元素”的意思吧。话说,如果不用乘法而是用加法分解整数的话,那么素数就只有1一个了,不过这样没什么研究价值,因此数学上就不研究它了。

将这个程序“make run”一下,当然会顺利运行啦。

1 alloca(1)(harib25a) - 图1 1 alloca(1)(harib25a) - 图2
运行结果 为了看清数列的开头,我们强制结束一下

嗯,看上去不错呢。这样一来,“纸娃娃系统”不但能用来给泡面计时,还能用来求质数了,太好了。

■■■■■

下面我们稍微修改一下这个程序,让它显示1万以内的质数。程序的修改很简单,只要把开头一句改成“#define MAX 10000”就行了,然后另存为sosu2.c。哦对了,这个程序需要在栈中保存很多变量(光flag[10000]就需要大概10KB的空间),因此在Makefile中指定的栈大小改为11k了。

然后我们来“make run”一下。咦?出现了一条神秘的警告:“Warning: can’t link __alloca”。我们不管它,继续执行,可运行后显示出奇怪的内容,然后就停止不动了。没办法,我们用Shift+F1强制结束。

显示1000以内的质数运行很正常,为什么sosu2.hrb就不行了呢?其实我们刚刚忽略的那条警告信息中暗含玄机,它其实是在提醒我们缺少一个叫__alloca的函数。

电脑上所使用的C语言编译器规定,如果栈中的变量超过4KB,则需要调用__alloca这个函数。这个函数的主要功能是根据操作系统的规格来获取栈中的空间。在Windows和Linux中,如果不调用这个函数,而是仅对ESP进行减法运算的话,貌似无法成功获取内存空间(小于4KB时只要对ESP进行减法运算即可)。

不过,在“纸娃娃系统”中,对于栈的管理并没有什么特殊的设计,因此也用不着去调用__alloca函数,可C语言的编译器又不是“纸娃娃系统”专用的,于是就会擅自去调用那个函数了。唉,C语言还是不让人省心啊。

为了解决这个问题,我们需要编写一个__alloca函数,只对ESP进行减法运算,而不做其他任何多余的操作。

■■■■■

好了,那我们就来编写alloca吧……慢着,在编写这个函数之前,我们可以先想个办法在程序中获取这10KB的内存空间。其实,笔者曾经写不出成功的alloca,当时就是用下面的方法将就的(笑)。

sosu3.c

  1. #include <stdio.h>
  2. #include "apilib.h"
  3. #define MAX 10000
  4. void HariMain(void)
  5. {
  6. char *flag, s[8]; /*这里!*/
  7. int i, j;
  8. api_initmalloc(); /*从此开始*/
  9. flag = api_malloc(MAX); /*到此结束*/
  10. for (i = 0; i < MAX; i++) {
  11. flag[i] = 0;
  12. }
  13. for (i = 2; i < MAX; i++) {
  14. if (flag[i] == 0) {
  15. /*没有标记的为质数*/
  16. sprintf(s, "%d ", i);
  17. api_putstr0(s);
  18. for (j = i * 2; j < MAX; j += i) {
  19. flag[j] = 1; /*给它的倍数做上标记*/
  20. }
  21. }
  22. }
  23. api_end();
  24. }

这样的程序应该就可以成功运行了,我们来试试看,“make run”。

1 alloca(1)(harib25a) - 图3

1万以内的质数

果然成功了!这样看来,问题果然出在alloca上(而并不是算法的局限所导致的)。