PrevNext

命令行基础

Resources
CPH

简单程序的编译过程

Linux

Resources
William Shotts
Ubuntu.com

适用于 Linux、Mac 和所有 Unix 终端

Mac

基本上与 Linux 相同……

打开终端应用并熟悉一些基本命令。如果还没有升级,请改用 zsh

Resources
Jim Hoskins
Rahul Saigal

键盘快捷键与终端命令

Armin Briegel

Windows

安装 g++

USACO(以及大多数比赛)使用 GCCg++ 编译并运行代码。要使用 #include <bits/stdc++.h> 头文件,必须安装 g++;详情请参阅在本地运行代码

在 Linux 上

大多数 Linux 发行版通常预装 GCC。可以用以下命令检查是否已安装:

whereis g++

如果没有预装,通常可以使用发行版的软件包管理器进行安装。

在 Mac 上

  1. 安装 XCode 命令行工具。

    xcode-select --install

    如果以前安装过,可能需要进行更新:

    softwareupdate --list # list updates
    softwareupdate -i -a # installs all updates

    完成这一步后,clang 应已安装(尝试在终端中运行 clang --version)。

  2. 安装 Homebrew

  3. 使用 Homebrew 安装 gcc

    brew install gcc

    根据这里的说明,如果 brew 长时间无法完成,那么:

    brew install gcc --force-bottle

    通常就足以解决问题。

  4. 此时应能使用 g++-# 编译,其中 # 是版本号(例如 10)。运行下面的命令:

    g++-10 --version

    应显示类似以下内容:

    g++-10 (Homebrew GCC 10.2.0_2) 10.2.0
    Copyright (C) 2020 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  5. 如果希望只输入 g++ 就能编译,可以创建 shell 别名。将下面这行放入 shell 的 rc 文件(使用 bash 时为 ~/.bashrc,使用 zsh 时为 ~/.zshrc)。

    alias g++=g++-10

    完成后,g++ --version 应与 g++-10 --version 输出相同内容。

    注意:不要通过符号链接或硬链接覆盖系统的 g++,因为这样几乎肯定会引发问题。如果不知道这些术语的含义,也不必担心。

在 Windows 上

较简单:Mingw-w64(适用于 Windows 的精简 GNU)

Resources
Microsoft

在 VS Code 中配置 MinGW

Jetbrains

在 CLion 中配置 MinGW

较困难:适用于 Linux 的 Windows 子系统(WSL)

如果已经习惯 Linux 命令行,这可能是最适合你的选择。

适用于 Linux 的 Windows 子系统通常简称 WSL,它在 Windows 系统内运行 Linux 内核(或模拟层,取决于使用的版本)。这样无需将 Linux 作为主操作系统,也能使用 Linux 二进制程序。

许多人(例如 Anthony)使用 WSL,但正确配置它可能有些困难。

Resources
Microsoft

对新手较为困难

如果想使用 (Neo)Vim 编程,可以安装 WSL 并通过 WSL bash 编写代码。

配置 WSL 后,可以运行以下命令安装必要工具。

对于 Ubuntu 等基于 Debian 的发行版:

sudo apt-get install build-essential

对于 Arch Linux 等基于 Arch 的发行版:

sudo pacman -Sy base-devel

网上可以找到许多美化 WSL、改善使用体验的教程。第一步是使用合适的终端,而不是 Windows 提供的默认终端。Microsoft Store 中的 Windows Terminal 是一个易用的选择。

Resources

配置终端

打造美观的命令行界面

在命令行中使用 C++

编译与运行基础

考虑下面这个简单程序,并将它保存为 name.cpp

#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
cout << "FOUND " << x << "\n";
}

编译并运行 C++ 程序并不困难。首先,在 Windows 上打开 PowerShell,在 Mac 上打开“终端”,或在 Linux 中打开所用发行版的终端。可以使用以下命令,将 name.cpp 编译成名为 name 的可执行文件:

g++ name.cpp -o name

然后执行程序:

./name

输入一个整数并按回车后,程序应当产生输出。也可以将这两个命令写在同一行:

g++ name.cpp -o name && ./name

注意,&& 能确保只有 g++ name.cpp -o name 成功完成后,./name 才会运行。

重定向输入与输出

如果想从 inp.txt 读取标准输入,请使用:

./name < inp.txt

如果想将标准输出写入 out.txt,请使用:

./name > out.txt

两者也可以同时使用,如下所示:

./name < inp.txt > out.txt

关于如何在程序内部进行文件输入输出,请参阅输入与输出

编译器选项(也称参数)

使用编译器参数可以改变 GCC 编译代码的方式。通常,我们会用类似下面的命令代替 g++ name.cpp -o name

g++ -std=c++17 -O2 name.cpp -o name -Wall
  • -O2 告诉 g++ 将代码编译得运行更快,但会增加编译时间(见此处)。
  • -std=c++17 允许使用 2017 年加入 C++ 的功能。USACO 已从 C++11 升级到 C++17。
  • -Wall 会检查程序中的常见错误。更多信息请参阅调试

编译时应始终使用这些参数。

添加快捷命令(Mac)

面向 Linux 与 Windows 用户

Linux 上的操作过程相似。如果使用 Windows,可以通过 IDE 获得这些快捷功能,也可以安装上文提到的 WSL。

反复输入上述编译器参数十分繁琐。应当定义快捷命令,这样就不必每次重新输入。

首先,如果 .zshrc 尚不存在,请创建它。

touch ~/.zshrc

使用文本编辑器打开 .zshrc

open ~/.zshrc

也可以使用其他文本编辑器(例如通过 subl 打开 Sublime Text)。

subl ~/.zshrc

可以在这里添加别名函数,例如用下面的内容在 Mac 上编译并运行 C++:

co() { g++ -std=c++17 -O2 -o "${1%.*}" $1 -Wall; }
run() { co $1 && ./${1%.*} & fg; }

现在可以在命令行中使用 co name.cpp && ./namerun name.cpp,轻松编译并运行 name.cpp。注意,函数中所有 $1 都会替换为 name.cpp,而 ${1%.*} 会移除 $1 的文件扩展名,得到 name

& fg 有什么作用?

假设 prog.cpp 是以下文件:

#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
cout << v[-1];
}

根据上面的资料,在 Mac 上要让 zsh 显示崩溃信息(例如段错误),必须使用 & fg。例如,考虑使用 run prog.cpp 运行上面的 prog.cpp

如果从上面的运行命令中移除 & fg,终端不会显示任何信息;保留它则会产生以下输出(忽略前两行):

[2] 30594
[2]  - running    ./${1%.*}
zsh: segmentation fault  ./${1%.*}

测量时间与内存用量(Mac)

例如,假设 prog.cpp 包含以下内容:

#include <bits/stdc++.h>
using namespace std;
const int BIG = 1e7;
int a[BIG];
int main() {
int sum = 0;
for (int i = 0; i < BIG; ++i) sum += a[i];
cout << sum;
}

那么 co prog.cpp && gtime -v ./prog 会得到以下结果:

  Command being timed: "./prog"
  User time (seconds): 0.01
  System time (seconds): 0.01
  Percent of CPU this job got: 11%
  Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.22
  Average shared text size (kbytes): 0
  Average unshared data size (kbytes): 0
  Average stack size (kbytes): 0
  Average total size (kbytes): 0
  Maximum resident set size (kbytes): 40216
  Average resident set size (kbytes): 0
  Major (requiring I/O) page faults: 91
  Minor (reclaiming a frame) page faults: 10088
  Voluntary context switches: 3
  Involuntary context switches: 38
  Swaps: 0
  File system inputs: 0
  File system outputs: 0
  Socket messages sent: 0
  Socket messages received: 0
  Signals delivered: 0
  Page size (bytes): 4096
  Exit status: 0

注意,10710^7 个整数需要 4107103400004\cdot 10^7\cdot 10^{-3}\approx 40000 KB 内存,与上面输出的 4021640216 十分接近,符合预期。

调整栈大小(Mac)

Warning!

本节内容可能已经过时。

假设 A.cpp 是以下程序:

#include <iostream>
using namespace std;
int res(int x) {
if (x == 200000) return x;
return res(x + 1);
}
int main() { cout << res(0) << "\n"; }

使用 g++ A.cpp -o A && ./A 编译并运行时,会输出 200000。然而,将 200000 改为 300000 后就会发生段错误。类似地:

#include <iostream>
using namespace std;
int main() {
int arr[2000000];
cout << arr[0] << "\n";
}

可以正常运行,但将 2000000 改为 3000000 也会发生段错误。这是因为 Mac 的栈大小默认似乎限制为 8 MB。

Resources
Wikipedia

问题说明

请注意,除通常的 256 MB 内存限制外,USACO 没有单独的栈大小限制。因此,在本地因栈溢出而崩溃的代码,仍可能在 USACO 服务器上通过。要让代码在本地运行,请使用以下方法之一。

Warning!

对于 Facebook Hacker Cup 这类需要提交本地程序运行结果的比赛,这一点尤其重要。

方法一

ulimit -s 65532 会将栈大小增加到约 64 MB。遗憾的是,更大的数值无法通过这种方式生效。

方法二

Resources
CF

人们每年都会抱怨 FHC

为绕过这一限制,可以传递一个链接器选项。根据 ld 的手册(在终端中输入 man ld),-stack_size size 选项具有以下作用:

指定程序主线程的最大栈大小。不使用该选项时,程序的栈大小为 8 MB。参数 size 是一个十六进制数,可以带有前导 0x。大小应为体系结构页面大小(4 KB 或 16 KB)的倍数。

因此,在编译命令中加入 -Wl,-stack_size,0x10000000,会将最大栈大小设为 16716^7 字节 256\approx 256 MB,通常已经足够。不过,将上面第一个程序中的 200000 替换为 1e7 后运行,仍会报错。这时可以进一步增大最大栈空间(例如将 0x10000000 改为 0xF0000000)。

在 Windows 上,将 -Wl,--stack,268435456 加入编译参数即可达到相同效果。268435456 表示 268435456 字节,也就是 256 MB。如果使用 Windows PowerShell,请务必用引号将它括起来(即 "-Wl,--stack,268435456"),因为逗号会被视为特殊字符。

Module Progress:

PrevNext