大多数系统调用以相同方式出错

大多数系统调用以相同方式出错 - 图1

由于系统调用依赖于程序以外的东西,所以它们一旦出错,就没办法控制。为了解决这个问题,系统调用总是以相同方式出错。

就拿execle()调用来说,判断exec()有没有出错很容易:如果exec()调用成功,当前程序就会停止运行。一旦程序运行了exec()以后的代码,就说明出了问题。

大多数系统调用以相同方式出错 - 图2

但仅仅告诉用户系统调用失败与否是不够的,通常你想知道系统调用为什么失败,因此几乎所有系统调用都遵循“失败黄金法则”。大多数系统调用以相同方式出错 - 图3

errno变量是定义在errno.h中的全局变量,和它定义在一起的还有很多标准错误码,如:

大多数系统调用以相同方式出错 - 图4

这样你就可以拿errno和这些值比较,也可以用string.h中的strerror()的函数查询标准错误消息:

大多数系统调用以相同方式出错 - 图5

当系统找不到你想运行的程序时就会把errno变量设置为ENOENT,以上代码就会显示这条消息:

  1. 没有该文件或目录

大多数系统调用以相同方式出错 - 图6练习

你可以在不同的机器上用不同命令查看网络配置。在Linux和Mac上,你可以用一个叫/sbin/ifconfig的程序;而在Windows上可以用ipconfig的命令,它的路径保存在命令路径中。

下面这个程序试图运行/sbin/ifconfig程序,如果失败就运行ipconfig命令。你不用传递任何参数给这两条命令,仔细考虑需要使用什么类型的exec()命令?

大多数系统调用以相同方式出错 - 图7

 

大多数系统调用以相同方式出错 - 图8练习解答

你可以在不同的机器上用不同命令查看网络配置。在Linux和Mac上,你可以用一个叫/sbin/ifconfig的程序;而在Windows上可以用ipconfig的命令,它的路径保存在命令路径中。

下面这个程序试图运行/sbin/ifconfig程序,如果失败就运行ipconfig命令。你不用传递任何参数给这两条命令,仔细考虑将使用什么类型的exec()命令?

大多数系统调用以相同方式出错 - 图9

 

这里没有蠢问题

问:system()不是比exec()简单吗?

:是的,但操作系统必须解释你传给system()的字符串,这可能引发错误,尤其当你动态创建命令字符串时。

问:为什么有那么多的exec()函数?

:人们想以不同的方式创建进程,于是创建了不同版本的exec()来提高灵活性。

问:为什么一定要检查系统调用的返回值?这样程序岂不是会很长?

:如果在进行系统调用时不检查错误,代码是短了,但可能引发更多的错误。最好在最初写代码时就考虑到错误,以后找起错来也简单。

问:调用了exec()函数以后还能做其他事吗?

:不能,只要让exec()函数执行成功,就会修改进程。它会运行新程序替代你的程序。也就是说,只要exec()函数一运行,你的程序就会停止运行。

 

大多数系统调用以相同方式出错 - 图10要点

  • 系统调用是操作系统中的函数。

  • 当进行系统调用时,相当于调用你程序外面的代码。

  • system()系统调用可以运行命令字符串。

  • system()用起来方便,但也容易出错。

  • exec()系统调用在运行程序时给了你更多控制权。

  • exec()系统调用有很多版本。

  • 系统调用出错时通常会返回-1,但不是绝对的。

  • 系统调用在出错的同时将errno变量设为错误码。

大多数系统调用以相同方式出错 - 图11弄乱的消息

星巴克的员工写了一个新的订单生成程序,他们管它叫coffee

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(int argc, char *argv[])
  4. {
  5. char *w = getenv("EXTRA");
  6. if (!w)
  7. w = getenv("FOOD");
  8. if (!w)
  9. w = argv[argc - 1];
  10. char *c = getenv("EXTRA");
  11. if (!c)
  12. c = argv[argc - 1];
  13. printf("%s with %s\n", c, w);
  14. return 0;
  15. }

为了检验程序,他们创建了这个测试程序。你能把代码片段和它们对应的输出结果连接起来吗?

大多数系统调用以相同方式出错 - 图12

 

大多数系统调用以相同方式出错 - 图13

大多数系统调用以相同方式出错 - 图14弄乱的消息解答

星巴克的员工写了一个新的订单生成程序,他们管它叫coffee

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(int argc, char *argv[])
  4. {
  5. char *w = getenv("EXTRA");
  6. if (!w)
  7. w = getenv("FOOD");
  8. if (!w)
  9. w = argv[argc - 1];
  10. char *c = getenv("EXTRA");
  11. if (!c)
  12. c = argv[argc - 1];
  13. printf("%s with %s\n", c, w);
  14. return 0;
  15. }

为了检验程序,他们创建了这个测试程序。你能把代码片段和它们对应的输出结果连接起来吗?

大多数系统调用以相同方式出错 - 图15

 

大多数系统调用以相同方式出错 - 图16