【问题标题】:Scope of parameters in a complex function definition复杂函数定义中的参数范围
【发布时间】:2015-03-05 20:20:51
【问题描述】:

考虑以下函数的模糊定义,该函数返回指向chars 数组的指针:

char (*func(int var))[sizeof var]
{
    return 0;
}

有效吗?

有问题的部分是sizeof 表达式中标识符var 的使用。至少根据 GCC 4.9.2,varsizeof 表达式中不可见。 (请注意,如果将 sizeof 表达式中的 var 替换为 42,则代码是有效的,这个问题就变得无趣了。)

然而,在 C11 规范草案 n1570 中(相关部分在 C99 中相同,尽管可能有不同的子条款编号),子条款 6.2.1 讨论了标识符的范围,并包含以下与此情况相关的句子:

6.2.1p4 包含:

如果声明符或类型说明符 声明标识符出现在块内或参数声明列表中 一个函数定义,标识符有块作用域,它终止于 关联块。

6.2.1p7 包含(加粗我的):

结构、联合和枚举标记的范围紧随其出现之后开始 声明标签的类型说明符中的标签。每个枚举常量的范围 在其定义的枚举数出现在枚举数列表中之后开始。 任何 其他标识符的范围在其声明符完成后开始。

显然,var 的声明符出现在函数定义的参数声明列表中。因此,根据 6.2.1p4,其范围在函数体(“关联块”)的末尾结束。此外,var 明显对应于 6.2.1p7 中提到的“任何其他标识符”,因此它的范围在其声明符完成后开始,即在参数列表的末尾。

在我看来,规范中没有提到与var 的范围相关的其他内容。鉴于规范没有另外说明,对范围的“开始”和“结束”的明显(对我来说,无论如何)解释意味着范围跨越从开始到结束的整个词汇区间。因此,var 似乎实际上应该在 sizeof 表达式中可见。

规范中有没有我没有说明的地方? 标识符的作用域的概念是否意味着以某种其他方式解释,而不是“从作用域开始到作用域结束的不间断词法区间”?如果是这样,这在规范中是如何体现的?

【问题讨论】:

  • 仅供参考,gcc 并不孤单。带有 -std=C11 的 clang 3.5 报告相同的错误(未声明的标识符:var)。

标签: c function parameters scope language-lawyer


【解决方案1】:

函数的返回类型在声明函数本身的块作用域或文件作用域中定义。它不属于函数定义的最外层块作用域。 在这个范围内(函数被声明的地方),函数的参数还没有被声明。

你可以考虑这样的函数定义

return type: char ( * )[sizeof var] // Oops..What is var?!
{
   // function block scope including its parameters declarations;
   int var;
}

【讨论】:

  • 类似于我对 Jens 的评论 - 这似乎是一种合理的行为,但我似乎无法从规范中得出这个结论(或与我在问题中提出的结论相矛盾)。跨度>
  • @SirDayBat 函数参数要么具有函数原型作用域,要么具有函数最外层块作用域。返回类型不是函数参数。
  • @SirDayBat 为函数参数定义单独的范围是有意义的,因为可以在许多函数的声明和定义中使用相同的参数名称。返回类型没有自己的特殊范围。
  • 是的,函数参数(在函数定义中)的作用域从其声明符之后开始,并贯穿函数的最外层块。而且我声称规范确实没有说对于函数声明符的其余部分暂时终止范围。关于此答案中的代码:如果在 C 中以这种方式声明返回类型,则 var 确实不可见。但就目前而言,使用 C 的语法,sizeof 表达式在词法上出现在 var 的声明之后(并且在 var 的范围结束之前),这应该是最重要的。
  • @SirDayBat 在我看来,该标准的引用很明确“如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表中,则标识符具有块作用域,它在关联块的末尾终止。”它说的是参数声明列表的声明符。函数本身的声明符不属于参数列表。
【解决方案2】:

[sizeof var] 部分根本不是块的一部分,也不是声明列表的一部分,而是返回类型的一部分。因此,唯一可见的标识符是具有文件范围的标识符。

【讨论】:

  • 所以你是说块范围标识符只能在块和函数定义的参数列表中可见?这似乎是一种合理的行为,但我无法从规范中推断出这一点。从规范中,我对标识符范围的理解是,它们从一个点开始,在另一个点结束,并且在其间的任何地方都可见(除非被另一个声明遮蔽)。而var 的作用域在其声明符之后开始,并在func 主体的末尾结束。我在规范中看不到任何暗示它在参数列表和正文之外不可见的内容。
  • @SirDayBat,因为它是返回类型的一部分,所以会有文件范围,不是吗?
  • @JensGustedt,如果在 sizeof 表达式中声明了某个标识符,那么该标识符将具有文件范围,是的。但除此之外,没有与未声明任何内容的表达式关联的范围。但是,我仍然没有看到(在规范中)会阻止具有文件范围的声明引用具有块范围的事物。我希望我没有误解你在说什么。无论如何,您能否参考支持此答案的规范的相关部分?
  • 我是说你会在作为文件范围声明的一部分的表达式中使用标识符,即函数的返回类型。如果是这样,则该标识符必须是该范围内的有效标识符,但它不是,它具有块范围。
  • 我想我明白你的意思了。但是规范真的这么说吗?不能在文件范围声明中使用块范围标识符?如果我对规范的理解正确,那么范围就不是单独的名称空间或任何东西——毕竟,文件范围标识符可以在块中使用,等等。据我所知,规范也没有禁止相反的情况。范围(文件、块等)的 类型 本身不会影响标识符的可见位置 - 只有范围的开头和结尾才有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2017-08-07
相关资源
最近更新 更多