我正在尝试学习 C++,但我甚至无法使用g++
命令或使cplusplus.org 中的第一个 (hello world) 示例工作c++
。我创建了一个与示例一样的文件并运行g++ myfile
,然后./myfile
。
我遇到权限问题,然后我使用chmod +x myfile
,权限问题消失了,但是发生了这个问题:
gzuspower@gzuspower:~/Desktop$ ./4
./4: line 1: //myfirst: No such file or directory
./4: line 4: syntax error near unexpected token `('
./4: line 4: `int main ()'
我调用了我的文件,4
因为这是我第四次尝试。这是在 Xubuntu 16.04 上。重复的问题答案不起作用,我尝试使用 .c、.cpp 作为文件扩展名,并尝试使用 firstc++(我的第一个尝试文件)而不是 4(我第四次尝试的文件),但没有任何效果。我将尝试不同形式的 hello-world 代码。
答案1
出了什么问题
运行chmod
您认为是编译器生成的文件几乎没有用。当编译器生成要执行的二进制文件时(即生成您的程序时),它会自动将其标记为可执行文件。如果您能够使用 --(chmod +x
您曾经这样做过)成功将文件标记为可执行文件,那么您的编译器也将能够执行相同的操作。如果您尝试运行您认为是编译器生成的程序,并且收到有关权限的错误,这通常意味着您正在运行错误的文件。
在这种情况下,特定的错误消息表明您正在尝试运行自己的 C++ 源代码文件。这绝对行不通。您需要运行编译器生成的文件,这是一个单独的文件。对于大多数编译器(包括),除非您通过将命令行参数传递给编译器来传递不同的输出文件名,否则将调用g++
此文件。您通常应该这样做。a.out
-o filename
此外,如果您的 C++ 源代码文件的名称不是以.cpp
、.cxx
、.cc
或结尾的.C
,则应该这样命名。此外,这区分大小写。以 结尾的文件.c
意味着C源代码,而不是 C++,即使您运行 C++ 特定的编译器命令(如)g++
,它也会被视为 C。大多数 C++ 编译器(包括g++
几乎所有在 Ubuntu 上运行的其他编译器)都会检查输入文件的后缀,以确定如何处理它们。有多种方法可以明确告诉您的编译器您的源代码是用什么语言编写的,但与以传统方式简单地命名源代码文件相比,它们很麻烦。
将目录更改为保存源代码文件的位置
您已经在文本编辑器中编写(或粘贴)了一些 C++ 代码并将其保存在文件中。首先确保您已导航到该文件所在的目录。在终端中,您可以使用cd
命令更改目录。打开终端窗口时,您通常位于主目录中。假设您的源代码文件名为hello.cpp
。然后,只有当它实际上位于您的主目录中时,运行类似命令g++ -o hello hello.cpp
才会成功hello.cpp
。如果它位于您的桌面上,则首先运行:
cd ~/Desktop
(该~/
部分代表您的主目录。如果您已经在终端中,则无需包含该部分。但我已将其包含在内,因为Desktop
无论您身在何处,该命令都会将您带到主目录的子目录。)
再举一个例子,如果您的桌面上有一个名为的目录source
,并且您已将源代码文件保存在该目录中,那么您可以通过运行以下命令在终端中到达该目录:
cd ~/Desktop/source
如果你有文件夹图标在文件浏览器中找到要访问的目录,然后输入cd
,输入Space,并将该图标拖到终端窗口中即可。这会将其完整路径名复制到终端中,然后您可以按Enter。
一旦你cd
进入源代码文件所在的位置,请检查它。例如,你可以运行此命令列出当前位置的所有文件(名称以 开头的文件除外.
,你可能不想看到这些文件):
ls -l
或者,您可以将源代码文件的文件名传递给ls
。例如,如果它被称为hello.cpp
,那么您可以运行:
ls -l hello.cpp
如果在执行此操作时看到此错误,则表示当前目录中没有该名称的文件:
ls: cannot access 'hello.cpp': No such file or directory
所以如果您看到这样的错误消息,那么无论如何都不要尝试使用g++
或c++
命令编译您的程序,因为它不起作用,因为您不在正确的位置。
尝试编译源代码,看看是否有错误
一旦你知道你在正确的位置,就尝试编译你的源代码文件,然后看看编译器是否报告它调用的任何内容错误成功编译并运行第一个程序后,您也应该开始留意编译器警告,因为它们通常会告诉您有关代码中问题的宝贵信息。它们还可以帮助解释错误。但是,了解错误和警告之间的区别很重要。尽管标准化 C++ 的所有文档都没有真正讨论过错误或警告(它们讨论的是“诊断”),但这种区别非常重要。错误是编译器告诉您它无法编译您的程序。
以下是您可能会看到的编译错误的示例:
hello.cpp:55:84: error: expected primary-expression before ‘<<’ token
请注意,编译器error:
在消息中包含了 。注意。您可能会收到许多不同类型的错误,具体取决于您的源代码以及您使用编译器的方式。它们看起来并不完全一样。但它们通常会显示error:
。
如果您尝试编译程序,但编译器生成了它称为错误的东西,而您忽略了它并尝试运行程序,那么就有三种可能性,而且都不是您所需要的。您可能正在运行编译器未生成的某些东西。这种情况发生在您身上:您尝试运行源代码文件本身。或者您可能试图运行一个根本不存在的文件。或者您可能正在运行编译器先前生成的某些东西在之前成功的编译期间,从而运行比您想要运行的程序更旧的版本。
考虑到这一点,您可以尝试通过运行以下命令来编译您的程序:
g++ -o hello hello.cpp
我说你会运行一个命令喜欢因为你需要将其更改hello.cpp
为 C++ 源代码文件的实际名称。你可能还想将hello
后面出现的更改-o
为其他文件名。这个文件名是编译器成功生成的程序,即如果没有错误。你可能不想打电话全部您的程序hello
。如果当前目录中已有一个名为的文件hello
,或者您在后面添加的任何名称-o
,则编译器将覆盖该文件。
如果有错误然后是时候试着找出哪里出了问题。也许源代码中有一个错误。也许你在编译时犯了一个错误。也许它需要将更多选项传递给编译器。有很多事情可能出错,虽然你很可能在大多数情况下都能弄清楚,但有时——甚至经常——你可能需要寻求帮助,这很好。当你寻求帮助时,你应该始终确保提供产生问题的小程序的完整源代码,并完整描述你所做的一切以及发生了什么,包括显示你运行的所有命令及其输出。
尝试运行你的程序并看看会发生什么
假设您-o hello
按照上面所示传递给编译器,并且编译成功。然后,您将尝试使用以下命令运行程序:
./hello
如果您看到这样的错误,则表示未找到您的程序:
bash: ./hello: No such file or directory
因此,如果发生这种情况,请回顾编译器的输出。检查是否有你错过的错误。同样,如果你看到这样的错误,则意味着你尝试运行的文件做存在,但实际上无法运行。此问题有多种可能的原因,但通常这意味着您正在尝试运行错误的文件:
bash: ./hello: Permission denied
之前,我描述了如何使用它ls -l
来查看当前目录中有哪些文件,或者检查特定文件。上下文是检查您是否处于正确的位置以开始尝试编译程序。但是在编译程序之后,如果您无法运行它并且不确定原因,那么该ls
命令就是您可以用来查看编译器是否真正创建了该文件的工具之一。
ls -l
运行(或者可能只是)有时可能会帮助您发现的一件事ls
是,如果您输入了错误的名称,并且在之后-o
(编译程序时)意外地写了一些与./
您尝试运行程序时写的内容不同的内容。
./
in的作用是告诉您的 shell 您想要运行位于当前目录中的./hello
名为 的文件。代表当前目录。如果您只输入并按下,而不使用前导,则 shell 将尝试查找并运行已安装的名为 的命令。这不是您想要的。您想要运行刚刚编译的位于当前目录中的特定文件。hello
.
hello
Enter./
hello
你看到了什么
最后,假设你尝试运行程序,并且看到包含其片段的消息源代码,就像这样,你确实看到了:
./4: line 1: //myfirst: No such file or directory
我甚至没有看过你的源代码,但我可以看出这看起来像是源代码的一个片段。具体来说,//myfirst
看起来像是你可能放在源代码顶部的单行注释的开头。虽然它可能的尝试运行程序时遇到问题,显示包含源代码文件中文本的消息,这种情况很少见。更常见的情况是,您意外尝试运行源代码文件,而不是编译器生成的二进制文件!因此如果您看到错误消息跑步一个 C++ 程序,看起来像是在引用你的源代码,请务必检查这一点。当您尝试运行 C++ 程序时,请始终运行编译器生成的文件,该文件与您自己编写的源代码文件不同。
完整的答案可以(并且已经)写下你看到这些特定消息的确切原因。但基本上,发生的事情是你曾经将chmod
源代码文件设为可执行文件,然后当你运行它时,它作为shell 脚本。该代码//myfirst
被解释为 shell(bash
在本例中为)中的代码,而不是 C++ 中的代码,它告诉 shell 尝试运行目录myfirst
中名为 my 的文件/
。没有这样的文件,所以你得到了一个错误。
不过,从更一般的角度来看,我建议记住:
- 如果你的编译器说了它称为“错误”,那么它不太可能创建您的程序。
- 如果你尝试运行程序,但看到毫无意义的输出,尤其如果输出包含似乎提到源代码部分的消息,请仔细检查程序是否真正创建,以及是否正在运行它,而不是运行你的源代码文件,或其他文件,或其他程序。
答案2
您错误地调用了编译器。您还应该对 C++ 文件使用.cc
或.cpp
文件扩展名。例如,编译器命令的正确用法应该是g++ hello-world.cpp -o hello-world
。
答案3
正如解释的那样Eliah Kagan 的回答,您看到的错误消息是因为您尝试执行源文件而发生的。在这里,我将尝试解释您为什么会收到这些特定消息。
当你给文件执行允许然后你尝试执行它通过运行/path/to/filename
(通常是./filename
),并且它是文本文件,它将作为脚本运行。脚本通常具有一条线作为第一行,紧接着#!
是目标的完整路径解释器。
当您尝试从 Bash shell 运行可执行文本文件时,如果该文件没有 shebang 行,Bash 会认为它是一个 shell 脚本,并启动一个新的 Bash shell 来运行它。(#!/bin/bash
如果运行它的 shell 不是 Bash,最好在 Bash 脚本的顶部写入。)但如果文件包含除 Bash 代码以外的内容,那么您通常会遇到大量语法错误。这就是你发生的事情,正如您收到的错误消息所示:
$ ./4
./4: line 1: //myfirst: No such file or directory
./4: line 4: syntax error near unexpected token `('
./4: line 4: `int main ()'
当 shell 尝试将文件作为 shell 脚本执行时,它会产生一个新的、非交互的shell 来解释脚本。这样,脚本可能会做的很多事情,比如更改目录或定义变量或函数,就不会有任何影响在调用 shell 上。我们可以测试非交互式子 shell(例如尝试运行源文件的 shell)的行为,方法是将输入发送bash
到这里的字符串, 像这样:
$ bash <<< 'echo Hello World!'
Hello World!
很多时候,仅在当前 shell 中运行该命令就会产生相同或相似的输出(例如上述情况),但我们可以通过这种方式更准确地重现您的错误消息。例如:
$ bash <<<'//myfirst C++ program'
bash: line 1: //myfirst: No such file or directory
根据错误,我猜测源文件第 1 行的内容。//
,它启动一行在 C++ 中注释,在 Bash 中不是注释。如果命令的第一个单词中包含/
,Bash 会将该单词视为路径。如果路径是可执行文件的路径,则将执行该文件。(这正是您运行 时发生的情况./4
:执行了路径为 的文件./4
。)如果没有这样的文件,那么我们会收到一条错误消息。
//
解析到根目录/
,并且由于它不包含myfirst
系统上调用的文件,所以您得到的是No such file or directory
。如果它包含匹配的文件,您可能会得到不同的错误:
$ bash <<< '/dev'
bash: line 1: /dev: Is a directory # matches, but it's a directory
$ bash <<< '/swapfile'
bash: line 1: /swapfile: Permission denied # matches, but not executable
你可能在 C++ 程序中使用的另一种注释风格,/*
*/
可能会产生更有趣或更混乱的结果,因为/*
会扩大到根目录中的所有非隐藏文件,并且*/
会扩展到当前目录中所有非隐藏的目录。
您没有收到有关第 2 行或第 3 行的任何错误。这可能是因为它们是空的,或者因为它们包含一些有效的 Bash 代码(可能性很小)但没有产生任何输出,或者它们有一行以 开头#
,这是 Bash 中的注释。例如,您可能有如下一行:
#include <iostream>
当 Bash 从文件运行命令时,它会假设任何以不带引号的开头#
是只为人类并忽略它。
然后在第 4 行你收到一个语法错误:
$ bash <<< 'int main()'
bash: line 1: syntax error near unexpected token `('
bash: line 1: `int main()'
(
并且)
是外壳元字符和控制运算符。它们可能会产生子壳在其中可以运行命令或命令列表。其常见用途是命令替换子 shell 中运行的命令的输出将替换外壳中的命令。当$
位于 之前时,就会发生这种情况(stuff)
。这是一个(有用的)示例:
$ which g++
/usr/bin/g++
$ readlink -e $(which g++)
/usr/bin/x86_64-linux-gnu-g++-7
双括号导致算术扩展:
$ bash <<< 'echo $((3+4))'
7
的另一种用法()
是表明前面的单词是一个正在定义的函数,如shell 函数定义中括号 `()` 有什么用?()
如果命令之前有两个单词,除非第一个单词是function
,否则(
会出现语法错误:
$ bash <<< 'foo bar()'
bash: line 1: syntax error near unexpected token `('
bash: line 1: `foo bar()'
$ bash <<< 'function bar()'
bash: line 2: syntax error: unexpected end of file
function
是可选的,没有它我们也会得到同样的错误。EOF 错误发生是因为我们还没有继续定义函数。
当 shell 遇到语法错误时,它会停止处理当前输入(如果是非交互式 shell,则会立即退出),因此无论接下来发生什么,您都不会看到任何进一步的错误。无论您的源文件在 之后继续说什么int main()
,shell 都不会读取它。
非常感谢 Eliah Kagan 鼓励我写下这个答案,提供各种有用的见解!