C++中的函数声明后不需要分号(';')吗?

Posted

技术标签:

【中文标题】C++中的函数声明后不需要分号(\';\')吗?【英文标题】:Isn't a semicolon (';') needed after a function declaration in C++?C++中的函数声明后不需要分号(';')吗? 【发布时间】:2019-07-14 09:44:22 【问题描述】:

我最近刚参加了中级编程考试,答错的题之一如下:

函数声明后不需要分号(';')。

对或错。

我选择了“false”(如果我错了请纠正我,因为我觉得我快疯了),一个函数 declaration 是你在定义之前写的(在顶部代码),因此编译器在调用函数之前就知道函数调用,而函数定义构成了整个函数。

即,

声明:

int func();

定义:

int func() 
  return 1;

这个答案不应该是假的吗?

【问题讨论】:

定义也是声明。但我会说你的答案是正确的。 这是一个棘手的挑剔问题,与任何人的编程能力无关。 我总能找到导致双重否定的问题,令人困惑。在我看来,这样的问题旨在让学生绊倒。为什么不能以以下方式形成问题:“在函数声明之后总是需要分号(';')。对或错。”? :// @phonetagger 所有这些混乱都表明这个问题的措辞是多么糟糕。 Hanlon's Razor 建议测试的作者混淆了“声明”和“定义”。 【参考方案1】:

很遗憾你提出的问题没有说“直接之后”。例如,我们可以这样写:

int func()  /* My function */ ;

或者我可以写:

int func()
int a = 42;

在第一种情况下,分号不是直接在声明之后,但这没关系。

在第二种情况下,声明“之后”有一个分号,但不是直接在之后。

我认为 Eric Lippert 在his answer 中的想法是正确的。

这就像在说“英语中的句子结束后应该有句号吗?”。可以说,一个句子的末尾已经有一个句点(否则它不会是一个句子),因此在句子之后不应该有句点..

【讨论】:

不错。用一个额外的句号结束这句话。我知道你在那里做了什么。 int func() int a=42; 无法编译。你需要一个逗号,而不是另一个int。请参阅在此之前一天发布的@Arne 的答案。这个答案中唯一的新东西是最后一段,类似于英语句子。 第二个例子我没说编译。我指出说在声明“之后”需要一个分号是模棱两可的。我的示例在声明后有一个分号,但它编译。 错误信息中也会出现同样的问题; C# 中最喜欢的示例是“params 参数必须是形式参数列表中的最后一个参数”。现在,假设我说“一个 frob 必须是 gloob 列表中的最后一个 gloob”。这是否意味着(1)每个 gloob 列表的末尾正好有一个 frob,就像每个问题的末尾都有一个问号一样,(2)一个 gloob 列表可以有任意数量的 frob,但如果它有一个或多个 frob , 最后一项必须是 frob,就像偶数可以有任意个 02468,但其中一个必须是最后一项,或者... ... (3) 一个 gloob 列表可以有 0 个或 1 个 frobs,如果它有 1 个,它会在最后吗?如果您不了解上下文,我认为(1)是最明智的解释,但在“params 参数”的情况下,(3)是正确的解释。许多关于编程语言元素的非正式描述都有一个属性,我的技术编辑朋友称之为“COIK”——仅在已知时清除。如果你还没有完全理解材料,描述它对你来说毫无用处,但如果你已经完全理解它,你就不需要描述了!【参考方案2】:

当函数在 main() 之前定义

不需要分号,因为函数已经定义了

当函数在main()之后定义

需要分号,因为您正在对该函数进行原型设计并告诉编译器该函数已退出。

【讨论】:

【参考方案3】:

分号 (;) 用于告诉编译器在该分号 (;) 之后开始一条新语句。

所以我认为分号 (;) 仅在函数声明期间是必需的。所以在我看来,答案是正确的。

【讨论】:

声明不是陈述。 但是在函数声明之后,我们正在使用编译器执行新的代码行。所以我认为在执行新的代码行之前,编译器必须知道前一行代码在哪里结束,然后编译器才能生成本机代码(即 0101)。【参考方案4】:

这是一个棘手的问题,但他们使用了声明这个词,意思是这样的:

int example();

所以在这种情况下是正确的。

如果他们使用了实施这个词,那么它就是错误的。

【讨论】:

【参考方案5】:

您只能将; 用于原型。

【讨论】:

【参考方案6】:

尽管我同意几乎所有其他答案,指出问题措辞非常模棱两可,而且您的回答在技术上是正确的,但请允许我给出不同的观点:

这是我一直以来的称呼:

void func();  // The function prototype

...

void func()

    // The function definition

我假设这个问题是根据这个术语提出的。

在我看来,定义和声明都是同一个概念。 "我定义 x = y" == "我声明 x = y"。

当然,函数原型(顶部)与函数的实际定义之间存在很大差异。

【讨论】:

对我来说,您的原型是基于我的学习方式的声明(虽然也不是说您错了),但我也希望原型能够指定参数的数量和类型,或者无效,但我希望您为简洁起见省略了。 David S:是的,当然它也会包含参数的数量和类型,但为了简洁起见,我确实省略了它们(请注意,实际函数声明中也没有参数)。但是,当您说完整的函数声明称为原型时,我真的不同意。我引用***:“函数原型或函数接口是函数的声明,它指定函数的名称和类型签名(arity、参数的数据类型和返回类型),但省略了函数体。” @DavidS:在 C++ 中,函数声明始终是原型(或定义),void func(); 完全等同于 void func(void);。这与 C 非常不同,其中void func(); 不会告诉编译器有关 args 的任何信息,并且与 void func(void); 不同。稍后的原型或定义是个好主意,否则调用者必须应用默认的 arg 提升(例如,float -> double 和窄整数类型到 int。与 args 到可变参数函数的规则相同。) 抱歉,我最终在这里查看了与 C 相关的内容,但没有注意到语言的变化。为了清楚起见,我不会删除我的评论,但认为它已撤回。【参考方案7】:

你也可以这样声明一个函数:

int func()
    return 1;

这个说法非常模棱两可。正确答案应该是:这取决于你如何声明函数。

无论如何,我也会选择 false,也许你可以向某人报告这个问题。

【讨论】:

无论如何,不​​要把事情放在个人层面。重要的是你理解了函数声明定义的工作原理,所以不要太担心,只要确保问题至少会被检查并继续 当然。老实说,我从错误的问题中学到了更多关于函数声明定义的知识。 @Logan 不要太担心。如果您知道如何编写和读取一个函数,这就是您所需要的。我个人讨厌这类问题 1. 定义不明确 2. 测试你对语法的理论知识。对我来说,这就像肌肉记忆。当我写下每个数字时,它会毫不费力地进入它应该去的键,但是如果你让我测试一下数字应该按什么键,如果没有键盘来实际执行操作,我将完全绝望...... ... 编写通用语法(例如函数)将成为您的第二天性。当您因为刚刚切换语言而将其搞砸时,嗯...智能感知和语法突出显示可提供快速有效的解决方案。将您的时间和精力投入到更有用的事情上。【参考方案8】:

函数声明后不需要分号(';')。

对或错。

正确。任何声明后都不需要分号。也不在任何定义之后。也不在任何声明之后。

许多声明必须以分号结尾,正如第 7 节 [dcl.dcl] 中的语法所指定的。但是之后就再也不需要写第二篇了。

【讨论】:

我看到 Eric Lippert 已经论证了这一点。我想所有的赞成票都让我忽略了它。随意在那里投票。 几乎所有的问题都会问,“X 总是对的:对还是错?”将得到“错误”的答案。哎呀,没有需要任何地方都有分号;编译器可能会抱怨并拒绝编译你的程序,但这并不是世界末日;我不会把它称为基本的需要。 ;) @Quuxplusone 如果编译器拒绝你的程序,你的程序中没有任何函数声明:)【参考方案9】:

这取决于我们是声明还是定义函数。 如果我们声明函数,我们需要包含分号(;),如果我们定义函数,则不需要分号。

声明如下:

int add(int, int);

一个定义是这样的:

int add(int a, int b)

    // ...

【讨论】:

这个答案的问题在于它表明定义和声明是相互排斥的。事实上,每一个定义都是一个声明;定义是声明的子集。【参考方案10】:

其他答案和 cmets 以多种方式指出这是一个可怕的、误导性的和写得不好的问题。但还有一个其他人尚未发现的问题。问题是:

函数声明后不需要分号(';')。对或错。

好的,我们来看一个函数声明:

int func();       /* */
/*           ^       */
/*           |       */
/* That whitespace is "after the function declaration". */

整件事就是声明。声明不是int func(),然后后跟;。声明是int func();,然后是空格。

那么,问题是:声明后是否需要分号?当然不是。 声明中已经有一个分号来终止它。 声明后面的分号是没有意义的。相比之下,int func(); ; 将是一个分号在函数声明之后

这个问题几乎肯定打算问“对还是错:函数声明中的最后一个标记始终是分号”但这不是他们写的问题,因为作者测验没有清楚地思考问题。

我的建议是完全避免编程语言测验。它们非常糟糕。


有趣的事实,而我们正在讨论这个主题。在 C# 中,这些都是合法的:

class C 
class D ;
struct E 
struct F ;

在 C# 中,类或结构声明可以以分号结尾,也可以不以分号结尾,由您自行决定。添加这个奇怪的小功能是为了让 C/C++ 程序员开始接触 C#,他们触手可及类型声明以无意义的分号结尾;设计团队不想因为他们有这个习惯而惩罚他们。 :-)

【讨论】:

评论不用于扩展讨论;这个对话是moved to chat。【参考方案11】:

除了“定义也是声明”的东西,下面是合法的C++:

int f(), g();

这声明了两个函数fg,它们都没有参数并且返回类型为int,但是f 的定义没有(立即)跟在分号后面。同样,这是合法的:

int f(), i = 42;

但是在这些情况下确实不允许完全省略分号,因此如果将其中任何一个作为没有后续分号的声明的示例,那将有些令人惊讶。事实上,以下是非法的:

void *p, f() 

除了(单纯的)函数声明之外,函数定义不能与任何其他声明或定义组合到同一个类型说明符。 (如果这是合法的,它将同时定义 void *pvoid f() 。)

无论如何,这似乎是一个“陷阱”类型的问题,不应该出现在中级编程测试中。

(哦,顺便说一句,请不要真的写像int f(), i = 42;这样的代码。)

【讨论】:

也可以使用 typedef 来定义函数类型,然后使用它一次声明多个函数,例如typedef int fooProc(int); fooProc a,b.c.d.e; 我不确定为什么基于软盘驱动器的编译器的标准头文件在当时没有这样做,因为我认为它可以让头文件变得更小,从而更快地处理。 还可以考虑int f(int(&g)(),int(*h)())return g()+h(); 这有三个函数声明,其中一个后跟一个左大括号,另一个后跟一个逗号,第三个后跟一个右括号。 @DavidHammen:除了int f(stuff) 之外,它并没有严格声明函数。即使在函数的范围内,g 也是函数引用类型的自动变量,h函数指针【参考方案12】:

您可能会在一个步骤中声明和定义函数,即,如果您在声明它的位置包含函数定义。所以 技术上 我认为 true 是正确的。但是这个问题的措辞是我会按照你的方式回答的。

【讨论】:

我认为 true 不正确,因为您给出的原因。如果在某些情况下需要分号,那么它是错误的(或不正确的)。真实对我来说是绝对的,如果有明确的情况需要它,那么你不能说真实。 @IFunball 好论据。愚蠢的母语。句子“函数声明后不需要分号(';')”可以读作“函数声明后不需要分号(';')(永远)”或“函数声明后不需要分号(';')(总是)”。是否将陈述限定为真或假取决于选择的解释。严格来说,这个问题不清楚,因此没有明确的答案。 @IFunball 这是因为“声明”,没有进一步的上下文,也没有声明我们是语言律师,通常被理解为“非定义声明”。这个问题不公平。 任何对知道正在测试的内容的人来说不清楚的考试问题都是错误的。 听起来我们需要在英语中添加一个未定义的行为子句

以上是关于C++中的函数声明后不需要分号(';')吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++父类中声明了一个虚函数以后 是否在子类 以及子类的子类中 都要声明并重写这个函数?

C++中的函数隐藏和使用声明

函数声明与函数定义的区别

我需要在新类中声明构造函数和析构函数吗?

朋友声明声明了一个非模板函数[重复]

为什么函数声明后可以不加分号而函数表达式后要加分号呢?