在 C 和 C++ 中作为语句的声明/定义

Declarations/definitions as statements in C and C++

提问人:Zebrafish 提问时间:4/17/2018 最后编辑:Matteo ItaliaZebrafish 更新时间:9/12/2019 访问量:7470

问:

当这不能在 C 中编译时,我感到很困惑:

int main()
{
    for (int i = 0; i < 4; ++i)
        int a = 5; // A dependent statement may not be declaration

    return 0;
}

我习惯了C++,这将编译。我只是目瞪口呆地盯着看了一会儿,直到我想起了 SO 上的一个答案,关于在 C 和 C++ 中不同的东西如何被视为“语句”。这是关于switch语句的。for 循环括号后面的“语句”必须同时存在于 C 和 C++ 中。这可以通过添加分号或创建 { } 波浪形括号块来完成。

在 C++ 中,“int a = 7;”被视为声明、定义和初始化。在 C 中,我相信它也被认为是所有这些,但在 C 中,它不被视为“语句”。

有人可以确切地澄清为什么在 C 中这不是一个语句,而在 C++ 中它是?这混淆了我对语句的概念,因为一种语言说它是,另一种说它不是,所以我有点困惑。

C++ C IF-语句 语言律师

评论

0赞 Zebrafish 4/17/2018
@NathanOliver我第一次注意到我的 Visual Studio 2017 上,包括 C 和 C++ 编译器,但我知道这不是合规性的一个很好的例子,所以我尝试了 onlinegdb.com,在两者中编译,这是一个示例,onlinegdb.com/SysJyUGnf 对不起,不确定这是使用 GCC 还是什么。但是,如果您切换到右上角的C++,您会看到两者之间的区别。
1赞 melpomene 4/17/2018
你在寻找什么样的答案?C++委员会关于为什么他们决定做与C不同的事情的声明?
1赞 Zebrafish 4/17/2018
@melpomene我开始明白这一点,一种语言中的一个定义不一定在另一种语言中具有相同的定义,这就是为什么它是另一种语言。只是在 C 和 C++ 中,如此相似,我期望像“语句”这样基本的东西是一个类似的概念,但这显然是很大的例外。我首先注意到这一点是在一个非常流行的问题中,关于跳过 C 和 C++ 切换语句中的初始化。
0赞 Tiger4Hire 4/17/2018
C语言有很多“方言”。最早的甚至根本不允许作用域变量。您必须在所有代码之前声明所有变量。例如,“K&R”C 则完全不同。您应该说明您正在使用的 C 版本。(C99 在现代编译器上最常见)。

答:

17赞 AndyG 4/17/2018 #1

C++ 允许迭代语句的“子语句”隐式是复合语句 ([stmt.iter])

如果迭代语句中的子语句是单个语句而不是复合语句,则就好像 它被重写为包含原始语句的复合语句。例:

while (--x >= 0)
   int i;

可以等效地改写为

while (--x >= 0) {
   int i;
}

C 标准没有这种语言。

此外,语句的定义在 C++ 中更改为包含声明语句,因此即使没有进行上述更改,它仍然是合法的。


添加大括号使其起作用的原因是,您的声明现在变成了一个可以包含声明的复合语句

您可以在不带大括号的循环体中具有标识符,因此您可以改为执行此操作:

int a = 5;
for (int i = 0; i < 4; ++i)
    a;

评论

0赞 Zebrafish 4/17/2018
明白了。您的报价与迭代相关,但是 int a = 7;仍然不被接受为 switch 语句中的语句。它说:“标签只能是语句的一部分,声明不是语句”。似乎不仅适用于迭代,尽管我可能误解了。
0赞 Zebrafish 4/17/2018
关于迭代的引用(例如 for, while)也必须适用于大小写标签,在 C++ 情况下 1:int a = 7;必须在 C++ 中被视为我猜的复合语句?而在 C 语言中则不是。
0赞 AndyG 4/17/2018
@Zebrafish:这可能 stackoverflow.com/q/92396/27678 有帮助
0赞 Y.T. 4/16/2023
对于第一个示例,如果声明不被视为语句,它是否仍是“单个语句”?
16赞 eerorika 4/17/2018 #2

在 C++ 中,语句是(C++17 标准草案)

excerpt from [gram.stmt]

statement:
    labeled-statement
    attribute-specifier-seqopt expression-statement
    attribute-specifier-seqopt compound-statement
    attribute-specifier-seqopt selection-statement
    attribute-specifier-seqopt iteration-statement
    attribute-specifier-seqopt jump-statement
    declaration-statement
    attribute-specifier-seqopt try-block

init-statement:
    expression-statement
    simple-declaration

declaration-statement:
    block-declaration

...

请注意,C++ 中有声明语句,它们是声明,是语句。同样,简单声明是 init 语句。不过,并非所有声明都是声明。声明的语法包含语句列表中没有的内容:

excerpt from [gram.dcl]

declaration:
    block-declaration
    nodeclspec-function-declaration
    function-definition
    template-declaration
    deduction-guide
    explicit-instantiation
    explicit-specialization
    linkage-specification
    namespace-definition
    empty-declaration
    attribute-declaration

block-declaration:
    simple-declaration
    asm-definition
    namespace-alias-definition
    using-declaration
    using-directive
    static_assert-declaration
    alias-declaration
    opaque-enum-declaration

simple-declaration:
    decl-specifier-seq init-declarator-listopt ;
    attribute-specifier-seq decl-specifier-seq init-declarator-list ;
    attribute-specifier-seqopt decl-specifier-seq ref-qualifieropt [ identifier-list ] initializer ;

...

声明语法列表继续了几页。


在 C 中,语句是(C11 标准草案)

excerpt from Statements and blocks

statement:
    labeled-statement
    compound-statement
    expression-statement
    selection-statement
    iteration-statement
    jump-statement

请注意,C 中没有声明是语句。


因此,语句的含义在语言中明显不同。 C++ 语句似乎比 C 语句具有更广泛的含义。

9赞 Abhishek Keshri 4/17/2018 #3

根据 cppreference,C++ 包括以下类型:statements

  1. 表达式语句;
  2. 复合语句;
  3. 遴选声明;
  4. 迭代语句;
  5. 跳转语句;
  6. 声明声明;
  7. 尝试块;
  8. 原子块和同步块

C 考虑以下类型:statements

  1. 复合语句
  2. 表达式语句
  3. 选择语句
  4. 迭代语句
  5. 跳转语句

正如你所注意到的,在C语言中不考虑声明,而在C++中则不是这种情况。statements

对于 C++:

int main()
{                                     // start of a compound statement
    int n = 1;                        // declaration statement
    n = n + 1;                        // expression statement
    std::cout << "n = " << n << '\n'; // expression statement
    return 0;                         // return statement
}                                     // end of compound statement

对于 C:

int main(void)
{                          // start of a compound statement
    int n = 1;             // declaration (not a statement)
    n = n+1;               // expression statement
    printf("n = %d\n", n); // expression statement
    return 0;              // return statement
}                          // end of compound statement

评论

0赞 Zebrafish 4/17/2018
我看到user2079303,你输入了相同的答案。在我看来,这个和另一个确切地解释了正在发生的事情。谢谢。
0赞 Abhishek Keshri 4/17/2018
乐于帮助:)是的,我发帖并注意到他得到了相同的答案,时差不到一分钟,哈哈;)
0赞 eerorika 4/17/2018
为了保持一致性,我也会在 C++ 示例中注释函数定义的复合语句。
2赞 Vlad from Moscow 4/17/2018 #4

在 C++ 中,声明是语句,而在 C 中,声明不是语句。所以根据这个for循环中的C语法

for (int i = 0; i < 4; ++i)
    int a = 5;

整数 a = 5;必须是循环的子语句。然而,这是一个声明。

例如,您可以使用复合语句使代码在 C 中编译

for (int i = 0; i < 4; ++i)
{
    int a = 5;
}

尽管编译器可以发出一条诊断消息,指出未使用该变量。a

另一个后果是,在 C 语言中,声明不是语句。在 C 语言中,您不能在声明之前放置标签。例如这个程序

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:
    int x = n;

    printf( "x == %d\n", x );

    if ( --n ) goto L1; 

    return 0;
}

不用 C 编译,尽管它编译为 C++ 程序。但是,如果在标签后放置一个 null 语句,则程序会编译。

#include <stdio.h>

int main(void) 
{
    int n = 2;

    L1:;
    int x = n;

    printf( "x == %d\n", x );

    if ( --n ) goto L1; 

    return 0;
}