【问题标题】:Why does `int ;` compile fine in C, but not in C++?为什么 `int ;` 在 C 中编译得很好,但在 C++ 中却不行?
【发布时间】:2016-01-21 06:58:33
【问题描述】:

考虑以下程序(参见现场演示here)。

#include <stdio.h>
int main(void)
{
      int ;  // Missing variable name
      puts("Surprise");
}

我的编译器 gcc 4.8.1 发出以下警告:

[警告]空声明中无用的类型名称[默认启用]

为什么编译得很好?我不应该得到编译器错误吗?当我将 g++ 4.8.1 编译为 C++ 程序时,会出现以下错误:

[Error] 声明没有声明任何东西 [-fpermissive]

【问题讨论】:

  • @Nawaz:语言规范有明确规定吗?
  • C++ 标准明确表示:“[dcl.dcl]/5simple-declaration 中,可选的 init-declarator-list 只有在声明一个类(第 9 条)或枚举(7.2)时才能省略,也就是说,当 decl-specifier-seq 包含一个 class-specifier、带有 class-key (9.1) 的 elaborated-type-specifierenum-specifier。 "我对 C 标准不够熟悉,无法引用章节。
  • “产生警告”不是“编译正常”。
  • 嗯,你可以同时定义多个本地人(int a, b, c;),对吧? int ; 看起来就像是同一事物的一个特例,声明了 0 个本地变量:D
  • -Werror重新编译

标签: c++ c gcc language-lawyer variable-declaration


【解决方案1】:

C 标准说

除了 static_assert 声明之外的声明应至少声明一个声明符(函数的参数或结构或联合的成员除外)、标记或枚举成员。

C++ 说

在简单声明中,可选的 init-declarator-list 只能在声明类(第 9 条)或枚举时省略。

任何一种语言的违规行为都需要进行诊断。这些标准不讨论编译器错误或警告。警告就是诊断。

【讨论】:

  • 您能否澄清该标准是否要求翻译在某些违规行为上失败? “错误”可以定义为产生诊断和故障的违规行为,而“警告”是产生诊断但没有故障的违规行为。
  • @tepples 不,标准只需要诊断。它不需要(但允许)拒绝无效程序。
  • 这意味着例如struct { int a; }; 声明了一个结构成员,但这还不够。
  • @n.m.: 所以这里需要结构的名称。对吗?
  • 需要标签或声明符。标签是struct a { ... }。声明者是struct { ...} a。声明符可以是变量名或 typedef 名(如果有 typedef 关键字)。
【解决方案2】:

您的代码在 C 和 C++ 中都是非法的(即错误的、格式错误的、违反约束的)。您在一种语言中收到“警告”而在另一种语言中收到“错误”的原因只是您的编译器和编译器设置的怪癖。毕竟,两种语言都没有真正正式区分“警告”和“错误”。 GCC 在其默认设置下恰好在 C 模式下更宽松(主要是出于历史原因)。

在 GCC 中使用-pedantic-errors,你也会在 C 代码中得到一个“错误”。 (请注意,-pedantic-errors 不会简单地将所有“警告”转变为“错误”。它会尝试仅将实际的约束违规报告为“错误”。)

【讨论】:

    【解决方案3】:

    声明的语法定义为(省略init-declarator-listinit-declarator):

    C11 6.7 声明

    declaration:
        declaration-specifiers init-declarator-list opt ;
        static_assert-declaration
    declaration-specifiers:
        storage-class-specifier declaration-specifiers opt
        type-specifier declaration-specifiers opt
        type-qualifier declaration-specifiers opt
        function-specifier declaration-specifiers opt
        alignment-specifier declaration-specifiers opt
    

    请注意,declaration-specifiers 是递归定义的,但每个带有 opt 表示它是可选的。

    此外,以下第 6 条规定:

    声明说明符由指示链接的说明符序列组成, 存储持续时间,以及声明符表示的实体类型的一部分。 initdeclarator-list 是一个逗号分隔的声明符序列,每个声明符都可能有额外的类型信息,或初始化器,或两者兼而有之。声明符包含被声明的标识符(如果有)

    注意这些词如果有的话

    【讨论】:

      猜你喜欢
      • 2015-08-21
      • 1970-01-01
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-10
      • 2016-12-30
      相关资源
      最近更新 更多