这个C++程序有什么问题?

11

当我编译这个程序:

#include<iostream>

using namespace std; 

std::cout<<"before main"<<endl;

int main()  
{

}

我在编译时看到了这个错误:

error: 在'<<'标记之前期望构造函数、析构函数或类型转换

请帮助我理解这意味着什么,我的程序有哪些问题?


10
为什么大多数C++编译器会给出如此糟糕的错误信息。 - log0
希望智能编译器可以生成更好的错误信息。 - Eric Z
1
在这种情况下,很难给出有意义的信息。即使clang也会说:“错误:名称空间'std'中没有名为'cout'的类型”以及针对operator<<的“错误:预期未限定标识符”。 - Tamás Szelei
@Ugo:对于人类来说,阅读并查看错误很容易,因为我们在错误点看到的上下文比编译器看到的要多。编译器只看到错误点之前的内容(也许还会看到一个或两个标记,以确定错误)。因此,如果理解了C++语法,错误就变得更加明显了。编译器看到了std::cout,现在正在寻找“构造函数、析构函数或类型转换”,因为这些是唯一能使声明或语句有效(从而成为有效程序)的下一个标记。 - Martin York
1
@Martin 我同意你的观点,我也知道编写编译器时可能会遇到的问题(真的)。但有时候这让我感到悲伤。例如,我们不得不等到gcc4.6才能获得“在|class|、|struct|和|union|定义后缺少分号的更清晰的诊断信息”……结构体在C语言中出现了将近40年了 :'(. - log0
5个回答

15
你看到了这个错误是因为你的
std::cout<<"before main"<<endl;

为了使这个程序有效,语句需要在你的 main() 函数(或其他函数)的范围内。

int main()
{
   std::cout<<"before main"<<endl;
}

与您的具体问题无关,还有一个要点:由于您正在using namespace std,因此在std::cout上显式添加std::是多余的。


6
在主函数中,返回一个整数是可选的。标准规定,在主函数结束括号之前会添加一个隐式的 return 0;。这仅适用于 main 函数,所有其他函数必须返回值,如果它们的签名指定了返回类型。 - David Rodríguez - dribeas
1
@David Rodriguez - 我同意,这就是为什么我说“应该返回”而不是“必须返回”。即使它是可选的,但这仍然是一个好的实践。 - razlebe
@abcd - 构造函数是一个函数,所以你的语句在那里是有效的。但你不能把一条语句单独放在源文件中间,这是没有意义的,也永远不会被执行。请参考@Nawaz的答案,了解语句在函数之外还有其他有效的情况。 - razlebe
1
为了清晰起见,我猜是这样的。标准规定(3.6.1/5)未从主函数显式返回等同于“return 0”,但根据我的经验,明确说明它永远不会有坏处。这个小程序没有问题。 - razlebe
@razlebe:我认为通常最好不要编写没有任何效果的代码。 - jalf
显示剩余5条评论

7

您不能进行编写

std::cout<<"before main"<<endl;

在函数外部。

-- 编辑 --
C++程序的唯一入口点是主函数。在执行主函数之前可能发生的唯一事情是静态/全局变量的初始化。

static int i = print_before_main_and_return_an_int();

是的,从我的程序输出中可以看出来...我想知道原因... - abcd
这容易出现初始化顺序问题。不能保证 couti 之前被初始化。 - David Rodríguez - dribeas
@abcd:嗯?你问什么是你程序的问题。问题在于你把std::cout放在了main函数之前。现在你是在问为什么这样做会出错吗? - jalf

7

语句不能在函数外执行。

然而,如果你把用于初始化全局变量的表达式放在那里,编译器不会产生任何错误或警告,这样做是可以的。

例如,下面的代码将打印出你想要的内容:

#include <iostream>

std::ostream &gout = std::cout<<"before main"<< std::endl;

int main() { }

输出:

before main

在线演示: http://www.ideone.com/Hz4qu


这里我做的事情与这个主题中所做的几乎相同:

main()真的是C ++程序的开始吗?


3
实际上,制作一个通用工具来实现它非常简单:http://www.ideone.com/Iotcc - GManNickG
1
这种情况是有问题的,因为它容易出现初始化顺序混乱的问题。没有保证gout的初始化会在std::cout之后发生,因此可能会导致您调用未初始化的cout上的operator<< -> 产生未定义的行为。 - David Rodríguez - dribeas
@Nawaz @David:我刚刚在我的博客上澄清了这个问题,因为它很有趣。http://www.gmannickg.com/?p=197 - GManNickG
@Nawaz:这段代码的作用是什么?std::ostream &gout = std::cout << "before main" << std::endl - Destructor
@PravasiMeet:gout是一个命名空间级别的变量,在main()开始之前必须进行初始化。但是为了初始化它,右侧必须被执行(结果会在stdout上打印字符串“before main”),并且返回值将作为引用存储在gout中。明白了吗? - Nawaz
显示剩余2条评论

3

您需要在函数内定义该行。

std::cout<<"before main"<<endl;

0
以上答案是正确的,但是还要补充一点。如果您已经有了:
#include<iostream>
using namespace std;

你不必输入:

std::cout<<"before main"<<endl;

你可以直接输入:

cout<<"before main"<<endl;

因为你已经声明了使用命名空间std;,这可以节省一些打字时间。祝好!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接