在C ++中进行函数声明后,不需要分号(';')吗?


174

我最近刚刚参加了一次中间编程测试,而我弄错的问题之一如下:

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

对或错。

我选择了“ false”(如果我做错了,请纠正我,因为我觉得自己快疯了),函数声明是您在定义之前(代码顶部)编写的,因此编译器知道该函数在调用它之前就调用它,并且函数定义是整个函数的组成部分。

宣言:

int func();

定义:

int func() {
  return 1;
}

答案不对吗?


41
定义也是声明。但是我会说你的答案是正确的。

216
这是一个棘手的挑剔问题,与任何人的良好编程能力无关。
phonetagger

40
我总是发现问题,导致双重否定,令人困惑。在我看来,此类问题旨在使学生感到困惑。为什么不能以以下方式形成问题:“在函数声明后始终需要分号(';')。对还是错。”?:/
AlgirdasPreidžius19年

18
@phonetagger所有这些混乱都表明了问题的措辞多么糟糕。
弗朗索瓦·安德里厄

34
Hanlon的Razor建议测试的作者将“声明”和“定义”混为一谈。
Sneftel

Answers:


161

您可能会遇到一种情况,即一步就声明并定义了函数,即,如果在声明函数的位置包括了函数定义。因此,从技术上讲,我认为true是正确的。但是问题的措辞使我会以您的方式回答。


10
我会说,由于您给出的原因,正确是不正确的。如果在某些情况下需要使用分号,则它为假(或不为真)。对我而言,正确是绝对的,如果有明确的情况需要,那么您就不能说正确。
I Funball

16
@IFunball很好的论点。愚蠢的母语。句子“在函数声明之后不需要分号(';')”可以理解为“ 在函数声明之后不需要分号)分号(';')”或读为“分号(';')”。 )不(总是)需要一个函数声明之后”。是否使陈述为真或假取决于选择一种解释。严格地说,这个问题尚不清楚,因此没有明确的答案。
彼得-恢复莫妮卡

6
@IFunball这是因为“声明”没有进一步的上下文,也没有声明我们是语言律师,通常被理解为“未定义的声明”。这个问题不公平。
Lightness Races in Orbit

2
任何对知道要测试内容的人不清楚的考试问题都存在错误。
纳特

2
听起来我们需要在英语中添加未定义的行为条款
Nick Mertin

147

除了“定义也是声明”之外,以下是合法的C ++:

int f(), g();

这声明了两个函数fg,都没有参数,返回类型为int,但是f没有立即对分号进行定义。同样,这是合法的:

int f(), i = 42;

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

void *p, f() {}

除了(单纯的)函数声明外,函数定义不能与其他任何声明或定义合并到同一类型说明符中。(如果这是合法的,它将同时定义a void *p和a void f() {}。)

无论如何,这似乎是“陷阱”类型的问题,不应在中间编程测试中使用。

(哦,顺便说一句,请实际上不要编写类似的代码int f(), i = 42;。)


2
也可以使用typedef定义一个函数类型,然后利用该类型立即声明许多函数,例如,typedef int fooProc(int); fooProc a,b.c.d.e;我不确定为什么基于软盘驱动器的编译器的标准头文件没有这样做一天,因为我认为这样做可以使头文件变得小很多,因此处理起来更快。
超级猫

还要考虑一下int f(int(&g)(),int(*h)()){return g()+h();}这有三个函数声明,其中一个后面是一个大括号,另一个是逗号,第三个是右括号。
大卫·哈门

1
@DavidHammen:这并不严格申报的功能比其他int f(stuff)。即使在函数范围内,它也是对函数g的类型引用的自动变量,并且h对函数指针
彼得·科德斯

83

其他答案和评论指出了这是一个可怕,误导且写得不好的问题的多种方式中的几种。但是还有另一个人尚未发现的问题。问题是:

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

OK,让我们看一下函数声明:

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#时便会受益,因为他们指尖可以将类型声明以无意义的分号结尾。设计团队不想因为这种习惯而惩罚他们。:-)


评论不作进一步讨论;此对话已转移至聊天
塞缪尔·柳

25

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

int func(){
    return 1;
}

该声明非常含糊。正确的答案应该是:这取决于您声明函数的方式。

无论如何,我也会选择false,也许您可​​以将问题报告给某人。


3
无论如何,不​​要把事情放在个人层面上。重要的是,您了解函数声明定义的工作原理,因此不必担心太多,只需确保至少可以检查问题并继续进行即可
Luca Corsini

11
绝对。老实说,我从错误的问题中学到了更多关于函数声明定义的知识,这比我正确理解该问题要多得多。
Logan

1
@Logan不必太担心。如果您知道如何编写和读取函数,则只需要这些。我个人讨厌这样的问题:1.定义不明确2.测试您的语法理论知识。对我来说,就像肌肉记忆。当我写每个数字不费吹灰之力地去找它应该去的键时,但是如果您对一个数字应该按什么键进行测试,我将完全没有希望
亲自

2
...编写通用语法(例如,像函数一样)将成为您的第二天性。而且当您因为刚刚切换语言而将其弄乱时,嗯...智能感知和语法突出显示可提供快速有效的解决方案。将时间和精力投入到更有用的事情上。
bolov

20

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

对或错。

真正。任何声明后都不需要分号。也没有任何定义。也没有任何声明。

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


1
我看到埃里克·利珀特(Eric Lippert)已经论证了这一点。我想所有的支持都使我忽略了它。随时在那里投票。
马克·范·吕文

几乎所有的问题都会问到:“ X始终为真:对还是错?” 答案将为“假”。哎呀,任何地方都不需要分号;编译器可能会抱怨并拒绝编译您的程序,但这还不是世界末日。我不会称其为基本需求。;)
Quuxplusone

@Quuxplusone,如果编译器拒绝您的程序,则您的程序中没有任何函数声明:)
Ben Millwood

6

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

声明是这样的:

int add(int, int);

定义是这样的:

int add(int a, int b)
{
    // ...
}

10
这个答案的问题是它表明定义和声明是互斥的。实际上,每个定义都是声明。定义是声明的子集。
MSalters '19

6

尽管我几乎同意所有其他答案,但指出该词措词非常含糊,并且您的答案在技术上是正确的,但请允许我给出不同的看法:

这就是我一直称呼他们的方式:

void func();  // The function prototype

...

void func()
{
    // The function definition
}

我以为这个问题是考虑到这个术语的。

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

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


对我来说,您的原型是基于我所学的方法的声明(虽然也并不是说您错了),但是我也希望原型能够指定参数的数量和类型,或者为void,但是我希望您省略该声明为了简洁。
David S,

David S:是的,当然它也会包含参数的数量和类型,但是为了简洁起见,我确实省略了它们(请注意,实际的函数声明中也没有参数)。但是,当您说完整的函数声明称为原型时,我并不完全同意。我引用Wikipedia:“函数原型或函数接口是函数的声明,它指定函数的名称和类型签名(arity,参数的数据类型和返回类型),但省略了函数主体。”
Opifex

@DavidS:在C ++中,函数声明始终是原型(或定义),并且void func();完全等同于void func(void);。这是很大的不同Ç,其中void func();并没有告诉有关ARGS编译任何东西,是不一样的东西void func(void);。稍后的原型或定义是个好主意,否则调用者必须将默认的arg提升(例如float-> double和窄整数类型应用于int。与可变参数函数的arg的规则相同。)
Peter Cordes

抱歉,我最终在这里看了一些与C相关的东西,但没有注意到语言的变化。为了清楚起见,我不会删除我的评论,但是认为它已撤回。
David S

6

很遗憾您提出的问题没有说“紧接着”。例如,我们可以这样写:

int func()  /* My function */ ;

或者我可以写:

int func()
int a = 42;

在第一种情况下,分号不是紧跟在声明之后,而是可以的。

在第二种情况下,在声明之后有分号,但不是在声明后。

我认为埃里克·利珀特(Eric Lippert)的回答是正确的。

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


4
真好 以额外的句号结束该句子。我知道你在那里做了什么。
David S

2
int func() int a=42;无法编译。您需要一个逗号,而不是另一个int。请参阅前一天发布的@Arne答案。此答案中唯一的新事物是最后一段,类似于英语句子。
彼得·科德斯

1
我没有说第二个例子已编译。我指的是,声明“在”之后需要分号是模棱两可的。我的示例在声明后使用了分号,但未编译。
尼克·加蒙

1
错误消息中也会发生同样的问题。C#最喜欢的示例是“ params参数必须是形式参数列表中的最后一个参数 ”。现在,假设我改为说“农作物一定是globo列表中的最后一个gloob”。这是否意味着(1)每个gloob列表的末尾都只有一个frob,就像每个问题的末尾都只有一个问号一样,(2)gloob列表可以有任意数量的frobs,但是如果它有一个或多个frobs ,最后一个项目必须是frob,例如偶数可以是02468,但是其中一个必须是最后一个,否则...
Eric Lippert

...(3)glolob列表可以包含零个或一个frobs,如果包含一个,则在末尾出现?如果您不了解上下文,我认为(1)是最明智的解释,但是对于“ params parameter”,(3)是正确的解释。编程语言元素的许多非正式描述都具有我的技术编辑者朋友称为“ COIK”的属性-仅在已知时清除。如果您还没有完全理解该材料,则对它的描述将毫无用处,但是,如果您已经完全理解该材料,则不需要该描述!
埃里克·利珀特


4

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

int example();

所以在这种情况下是真的。

如果他们使用了实现一词,那将是错误的。


2

使用分号(;)告诉编译器,在此分号(;)之后,新语句开始。

因此,我认为仅在函数声明期间才需要使用分号(;)。因此,根据我的说法,答案将是正确的。


声明不是声明。
HolyBlackCat

但是在函数声明之后,我们正在使用编译器执行新的代码行。因此,我认为在执行新的代码行之前,编译器必须知道上一行代码的结束位置,然后编译器才能生成本机代码(即0101)。
加特林德19'Mar

2

在main()之前定义函数时:

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

在main()之后定义函数时:

  • 需要分号,因为因为您要对该函数进行原型设计并告诉编译器该函数已退出。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.