ISO C是否允许提供给main()的argv []指针的别名?

Iwi*_*ist 17 c alias parameter-passing language-lawyer c11

ISO C要求托管实现调用名为的函数main.如果程序接收到参数,它们将作为char*指针数组接收,这是main定义中的第二个参数int main(int argc, char* argv[]).

ISO C还要求argv数组指向的字符串是可修改的.

argv别名的元素可以相互影响吗?换句话说,可以存在i,j使得

  • 0 >= i && i < argc
  • 0 >= j && j < argc
  • i != j
  • 0 < strlen(argv[i])
  • strlen(argv[i]) <= strlen(argv[j])
  • argv[i] 别名 argv[j]

在计划启动?如果是这样,argv[i][0]也可以通过别名字符串看到写入argv[j].

ISO C标准的相关条款如下,但不允许我最终回答这个名义上的问题.

§5.1.2.2.1程序启动

在程序启动时调用的函数被命名main.该实现声明此函数没有原型.它应定义为返回类型int且没有参数:

int main(void) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

或者有两个参数(这里称为argcargv,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):

int main(int argc, char *argv[]) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

或同等学历; 10)或以某种其他实现定义的方式.

如果声明它们,main函数的参数应遵循以下约束:

  • argc应为非负值.
  • argv[argc] 应为空指针.
  • 如果值argc大于零,则argv[0]通过argv[argc-1]包含的数组成员应包含指向字符串的指针,这些指针在程序启动之前由主机环境给出实现定义的值.目的是在程序启动之前从托管环境中的其他地方向程序提供信息.如果主机环境不能提供大写和小写字母的字符串,则实现应确保以小写形式接收字符串.
  • 如果值argc大于零,则指向的字符串argv[0]表示程序名称; argv[0][0]如果程序名不能从主机环境获得,则应为空字符.如果值argc大于1,则argv[1]through 指向的字符串argv[argc-1]表示程序参数.
  • 数组指向的参数argcargv字符串argv应由程序修改,并在程序启动和程序终止之间保留它们最后存储的值.

通过我的阅读,名义问题的答案是"是",因为它没有明确禁止,标准没有任何地方敦促或要求使用 - char* restrict*资格argv,但答案可能会转向解释"并保留其最后 -程序启动和程序终止之间存储的值." .

这个问题的实际意义在于,如果对它的回答确实是"是",那么希望修改字符串的便携式程序argv必须首先执行(相当于)POSIX strdup()以确保安全.

Joh*_*ger 9

通过我的阅读,名义上的答案是"是",因为它没有明确禁止,标准敦促或要求使用限制合格的argv,但答案可能会转向解释"并保留其最后一个 - 程序启动和程序终止之间的存储值."

我同意标准没有明确禁止参数向量的元素成为彼此的别名.我不认为可修改性和价值保留条款与该立场相矛盾,但它们确实向我建议委员会不考虑混淆的可能性.

这个问题的实际意义在于,如果它的答案确实是"是",那么希望修改argv中的字符串的可移植程序必须首先对它们执行(相当于)POSIX strdup()以确保安全.

实际上,这正是我认为委员会甚至没有考虑这种可能性的原因.如果他们做了那么肯定他们将有至少包含一个脚注到同样的效果,要不然明确指定的参数字符串是完全不同的.

我倾向于认为这个细节没有引起委员会的注意,因为在实践中,实现确实提供了不同的字符串,而且因为程序很少修改它们的参数字符串(尽管修改argv它本身更为常见).如果委员会同意在这个领域发布官方解释,那么我不会对他们反对混淆的可能性感到惊讶.

直到除非这样的解释被发布,但是,你是正确的,严格一致不允许你依靠先天argv不被混淆的元素.


Joh*_*nck 6

它在常见的*nix平台(包括Linux和Mac OS,也可能是FreeBSD)上工作的方式是argv指向一个包含参数字符串的单个内存区域的指针数组(仅由空终止符分隔).使用execl()不会改变这一点 - 即使调用者多次传递相同的指针,源字符串也会被多次复制,对于相同的(即别名的)指针没有特殊的行为(一种不常见的情况,优化没有太大的好处).

但是,C不需要此实现.真正的偏执者可能希望在修改它之前复制每个字符串,如果内存有限则可能会跳过副本,并且循环argv显示没有任何指针实际上是别名(至少在程序打算修改的那些中).除非您正在开发飞行软件等,否则这似乎过于偏执.

  • "飞行软件之类"不会一开始就修改命令行参数 - 提供保证证据的努力/成本将超过允许开发人员采用这种快捷方式的数量级.即使(假设)允许这样的事情,工具链(以及它发出或使用的代码)的保证与确保构建实际软件同样重要 - 将对系统设计中的假设进行交叉检查.工具链.编译器及其启动代码不被视为黑盒子. (3认同)