出口状态可观察到的行为吗?

时间:2018-12-17 13:14:18

标签: c language-lawyer main exit exit-code

C 2018 5.1.2.3 6说:

  

符合标准的实现的最低要求是:

     
      
  • 严格根据抽象机的规则评估对易失对象的访问。

  •   
  • 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。

  •   
  • 交互式设备的输入和输出动态应按照7.21.3的规定进行。这些要求的目的是尽快显示未缓冲或行缓冲的输出,以确保在程序等待输入之前确实出现提示消息。

  •   
     

这是程序的可观察行为。

表面上,这不包括程序的退出状态。

关于exit(status),7.22.4.4 5说:

  

最后,控制权返回到主机环境。如果status的值为零或EXIT_SUCCESS,则返回实现成功终止的实现定义形式。如果status的值为EXIT_FAILURE,则返回实现定义的状态不成功终止的形式。否则,返回的状态是实现定义的。

该标准没有告诉我们这是可观察到的行为的一部分。当然,exit的这种行为纯粹是对C抽象机器的描述是没有道理的;除非在环境中可观察到,否则将值返回给环境没有任何意义。因此,我的问题不是出口状态是否可观察,而是C标准对可观察行为的定义是否存在缺陷。还是标准中其他地方有文字?

2 个答案:

答案 0 :(得分:0)

我认为可以将其组合在一起,以使答案落在§5.1.2.3.6的第一个要点之内:

  

严格根据以下内容评估对易失对象的访问   抽象机规则

进一步,第3.1节将“访问”定义为:

  

读取或修改对象的值

和第3.15节将“对象”定义为:

  

执行环境中的数据存储区域,内容   可以代表值

奇怪的是,该标准未包含“易失性对象”的定义。它确实包含第6.7.3.6节中“具有挥发限定类型的对象”的定义:

  

具有挥发限定类型的对象可以通过以下方式修改   实现未知或具有其他未知副作用。   因此,引用此类对象的任何表达应为   严格按照抽象机的规则进行评估,如   在5.1.2.3中进行了说明。

推断具有volatile限定类型的对象具有该限定条件的目的恰恰是要告知编译器实际上它是一个volatile对象,这似乎是不合理的,因此,我认为它不会扩展太多东西以至于无法使用该措辞是“易失性对象”本身定义的基础,并将易失性对象定义为可以以实现方式未知的方式修改或具有其他未知副作用的对象。

第5.1.2.3.2节对“副作用”进行了如下定义:

  

访问易失性对象,修改对象,修改文件或   调用执行任何这些操作的函数   效果,即执行环境状态的变化。

所以我认为我们可以将其组合如下:

  1. 返回要返回到主机环境的退出状态是 明显改变了执行环境的状态,因为 例如,收到后的执行环境 EXIT_SUCCESS必须处于不同的状态 是否收到了EXIT_FAILURE。返回出口 因此,根据§5.1.2.3.2

  2. ,状态为副作用
  3. exit()是执行此操作的函数,因此调用exit()是 根据§5.1.2.3.2本身也有副作用。

  4. 该标准显然没有提供给我们有关内部工作原理的详细信息 exit()exit()将使用什么机制将值返回给 主机环境,但是假设访问 不会涉及对象,因为对象是数据区域 存储在执行环境中,其内容可以表示 值,退出状态是一个值。

  5. 由于我们不知道主机环境会做什么,如果有的话 响应状态变化(尤其是因为我们的程序 会在发生之前退出),此访问权限未知 效果,因此访问的对象是易失性对象。

  6. 由于调用exit()访问了易失性对象,因此可以观察到 根据§5.1.2.3.6。

这与对具有volatile限定类型的对象的常规理解是一致的,即,如果我们不能确定不会因为需要观察到的行为而忽略不需要的副作用,就无法优化对此类对象的访问。如果这样做的话,正常的日常感)可能会受到影响。当然,在这种情况下,没有可见的volatile限定类型的对象,因为volatile对象是问题,exit()是在内部访问的,exit()显然甚至不需要用C编写。但是似乎无疑是易失性对象,第5.1.2.3节专门(三次)指代易失性对象,而不是易失性限定类型的对象(除了6.2.4.2节的脚注以外,这是唯一的地方)是指标准的易失性对象。)

最后,这似乎是使第5.1.2.3.6节易于理解的唯一读物,从直觉上讲,我们希望仅使用标准描述的功能,C程序的“可观察到的行为”才是宽松的:

  • 以一种在程序本身之外可见的方式更改内存;
  • 更改文件的内容(根据定义,这些内容在 程序本身);和
  • 影响与交互式设备的交互

这实际上是第5.1.2.3.6节试图达到的目标。

修改

在注释中似乎没有什么争议,这些注释显然围绕这样的思想,即退出状态可以在寄存器中传递,而寄存器不能是对象。这种异议(无双关语)可以轻易驳斥:

  1. 可以使用register存储类说明符声明对象,并且可以通过左值指定这些对象;

  2. 内存映射寄存器在嵌入式编程中非常普遍,提供了与任何寄存器都可以是对象,可以具有地址并可以由lvalues进行指定一样清晰的演示。实际上,内存映射寄存器是volatile限定类型最常见的用途之一;

  3. mmap()表明,即使文件内容有时也可以具有地址并且可以是对象。

通常,认为对象只能驻留在核心存储器或DRAM芯片组中的位置或“地址”只能指代其内的错误是错误的,或者其他通常被称为“内存”或“ RAM”。执行环境中能够存储值(包括寄存器)的 Any 组件可以是一个对象,可以有一个地址,并可以由一个左值指定,这就是为什么定义标准中的“对象”是用这种故意宽泛的术语来表达的。

此外,第5.3.2.1.9节之类的内容会花一些时间来区分“实际对象的值”和“抽象语义所指定的[值]”,这表明实际对象是存在的真实事物正如第3.15节中对“对象”的定义所阐明的那样,在与抽象机器不同的执行环境中,规范确实确实与之密切相关。似乎一直无法维持这样一个立场,即标准直到在调用标准库函数之前(直到直到调用标准库函数为止)都与此类实际对象有关,在这种情况下,所有此类关注点都消失了,这些问题突然变成了“ C外部”。

答案 1 :(得分:-1)

我已阅读gtm.js功能文档(7.22.4.8系统功能)。它包含:

  

返回

     

如果参数为空指针,则仅当a   命令处理器可用。如果参数不是空指针,则系统   函数确实返回,它返回实现定义的值。

对于系统来说,这似乎是标准的规定,在该系统中,C程序(或更笼统地说是用户定义的命令)无法启动另一个命令,并且/或者该命令不会向其调用者返回任何内容。在后一种情况下,退出值将无法观察(在通常意义上)。

在这种解释中,退出值的可观察性只是实现定义。这与在程序的可观察行为中未明确引用它是一致的。

我记得上世纪70年代的一个旧系统(Solar 16),其中命令以system(对于标准命令)或call(对于用户命令)开始,并且只能传递参数在程序发出特定请求后,在子命令上进行操作。那里没有C编译器,但是如果有人设法实现一个C编译器,则返回值将无法观察。