Command-Line Compilation - C Plus Plus

  1. Which command most reliably selects the required language standard, names the executable correctly, and runs it after compilation succeeds?
    Answer: clang++ -std=c++20 main.cpp -o app && ./app When working with C++ compiler commands, you need to think about three independent concerns simultaneously: the language standard flag, the output binary name, and what happens after compilation. std::span was introduced in C++20, meaning the compiler must be explicitly told to use that standard — you cannot rely on the default, which might be C++14 or C++17 depending on the compiler version. The flag -std=c++20 communicates this requirement correctly. Combined with -o app to name the executable and && ./app to run it only if compilation succeeds, option B gives you exactly what the passage demands: standard enforcement, correct naming, and conditional execution. Option A fails at the first step — -std=c++17 predates std::span, so the code will not compile at all. You'd get a "not found" or similar error before ever producing a binary. Option C compiles with the correct standard but omits -o app, so the compiler defaults to naming the output a.out rather than app — a subtle but concrete failure to meet the stated requirement. Option D uses the flag -std=c20, which is not valid syntax for Clang; the correct form always uses c++20 (with the ++), not c20. This flag would be rejected or silently ignored depending on the version, making compilation unreliable. A handy pattern to memorize: for C++, the flag is always -std=c++[version] (e.g., c++17, c++20), never c[version]. Whenever a question specifies a feature and says "the default is not guaranteed," that's your signal that an explicit -std= flag is non-negotiable.
  2. Which command correctly performs both operations, running the program only if compilation succeeds?
    Answer: g++ src/main.cpp -o bin/demo && ./bin/demo When working with compiler commands, you need to think about two things simultaneously: the **syntax of g++ and the shell operators** that chain commands together. The g++ compiler follows a specific argument order: the source file(s) come first, then the -o flag followed immediately by the desired output path. So g++ src/main.cpp -o bin/demo tells the compiler "compile this source file and name the output bin/demo." The && operator then runs ./bin/demo only if compilation succeeds (exits with code 0) — exactly what the question requires. That makes A the correct answer. B flips the -o flag and the source file, writing g++ -o src/main.cpp bin/demo. This tells the compiler to name the output src/main.cpp and treat bin/demo as the source — completely backwards. The compiler will error out or corrupt your source file. C omits the -o flag entirely, so bin/demo is interpreted as a second source file to compile, not the output name. Without -o, g++ defaults to creating a.out, which is why C then tries to run ./a.out — but that logic is still broken because compilation would fail trying to find bin/demo as source. D uses the correct compilation command (g++ src/main.cpp -o bin/demo) but then runs ./a.out instead of ./bin/demo. The executable was placed in bin/demo, so ./a.out either runs a stale file or fails entirely. A quick memory aid: think "-o" = "output" — the flag always points forward to where you want the result to land.
  3. Which command should the student now use to run the executable that was just created?
    Answer: ../a.out When working with compiled C++ programs, you need to track two things: where the compiler places the output file, and where you are when you try to run it. By default, g++ places the compiled executable in the current working directory at the time of compilation — not in the source file's directory. The student compiled from /home/lee/project, so the executable a.out (the default output name when no -o flag is given) was created at /home/lee/project/a.out. After running cd src, the student is now inside /home/lee/project/src/. To run a file in the parent directory from your current location, you use ../ to navigate one level up. So the correct command is ../a.out, which is D. Here's why the other options fail: A (./main) is wrong on two counts — the executable isn't named main (no -o main flag was used), and ./ looks in the current directory (src/), where no executable exists. B (./a.out) gets the filename right but looks in the wrong directory — again, ./ searches the current src/ folder, not the parent where a.out actually lives. C (../main.cpp) is the source file itself, not an executable — you can't "run" a .cpp file this way; it's not compiled output. A helpful mental habit: always ask yourself "where was I standing when I ran g++?" That's where your a.out lives. Then figure out the relative path from your current position to get there.
  4. What is the resulting behavior of this command sequence?
    Answer: START is printed, FINISHED is not printed, and the sequence has exit status 2. When you chain shell commands with &&, each command only runs if the previous one exited with status 0. This question tests whether you understand how a program's return value from main becomes its exit status and how that interacts with shell command chaining. Here's the logic: g++ compiles successfully, so it exits with 0, allowing ./a.out to run. The program prints START, then executes return 2 from main. That 2 becomes the process's exit status — the OS receives it, and the shell sees a non-zero result. Because ./a.out exited with a non-zero status, the && operator short-circuits and echo FINISHED never runs. The overall sequence's exit status is 2, the last non-zero status encountered. This makes C correct. A is wrong because return 2 doesn't prevent execution — it's just the exit status returned after the program finishes normally. The program runs completely; START is definitely printed before the return. B is wrong because && requires every command in the chain to succeed (exit 0) before proceeding. Since ./a.out returns 2, the shell stops and skips echo FINISHED. D is wrong because the compiler exits with 0 (compilation succeeded), and START is printed during the program's run — it doesn't disappear just because the exit code is non-zero. A useful rule of thumb: in shell scripting, 0 means success and anything non-zero means failure. Whenever you see && chaining, ask yourself whether each step returns 0 — if not, the chain breaks right there.
  5. Which explanation best describes the likely result?
    Answer: The shell reports that the command was not found because it searches PATH, not the current directory automatically. When you type a command in a Unix-like shell, the shell doesn't search your entire filesystem — it only looks through the directories listed in your PATH environment variable, in order. The current directory (.) is almost never in PATH by default, and this is intentional: it's a security measure to prevent accidentally running malicious programs named after common commands. When you type a.out, the shell searches each directory in PATH, finds no match, and reports something like command not found. To explicitly run a file in the current directory, you must prefix it with ./, which tells the shell exactly where to look. That makes D the correct answer. A is false because g++'s default output name a.out has no special restriction — the file is a valid executable. No renaming is required; the issue is solely about how the shell resolves command names. B gets things exactly backwards. The current directory is not automatically searched before PATH — in fact, it typically isn't searched at all unless you explicitly add . to your PATH (which is discouraged for security reasons). C invents a behavior that doesn't exist. The shell has no memory of your last compilation command and makes no association between a bare filename and a compiler invocation. The shell simply looks up the command name in PATH. A good study habit here: whenever you see a question involving running a program, ask yourself who is doing the searching and where they're looking. The shell searches PATH; ./ bypasses that search entirely by specifying a path directly.
  6. Which command most directly builds a complete executable named app and runs it after a successful build?
    Answer: g++ main.cpp helper.cpp -o app && ./app When compiling a multi-file C++ project, your goal is to give the compiler every .cpp file that contains definitions your program needs — then link them all into one executable. Header files (.hpp) are not compiled directly; they're textual inclusions that the preprocessor handles automatically when it processes the .cpp files that #include them. Option A is correct because it hands g++ both main.cpp and helper.cpp. The compiler translates each into object code, the linker resolves the call to helper() by finding its definition in helper.cpp, and the -o app flag names the resulting executable. The && operator then runs ./app only if the build succeeds — a clean, safe pattern. Option B fails because listing helper.hpp instead of helper.cpp gives the compiler a declaration with no definition. The linker will throw an "undefined reference to helper()" error because the actual function body is never compiled in. Option C omits helper.cpp entirely. main.cpp will compile fine on its own, but the linker still can't find the definition of helper() — same undefined reference error as B. Option D goes the other way: it compiles only helper.cpp, which has no main() function. The linker can't build an executable without an entry point, so you get a "undefined reference to main" error. A useful rule of thumb: **every .cpp file that contributes definitions to your program must appear on the g++ command line** (or be compiled separately into object files). Headers never do.
  7. Which command correctly handles both filenames and runs the program only after successful compilation?
    Answer: g++ "hello world.cpp" -o "hello world" && "./hello world" When working with shell commands in C++, you need to think carefully about two separate issues: how the shell parses arguments and **how the && operator chains commands**. Any filename containing spaces must be quoted so the shell treats it as a single token — without quotes, a space acts as an argument separator. Option B is correct. It quotes "hello world.cpp" so the compiler sees one source file, quotes "hello world" after -o so the output name is treated as a single string, and uses && so the program only runs if compilation succeeds. The ./ prefix properly specifies the current directory, and quoting the executable "./hello world" keeps the name intact — all four pieces work together correctly. Option A fails immediately because hello world.cpp is unquoted. The shell splits this into two tokens: hello (no such file) and world.cpp (also nonexistent), causing a compilation error before anything else can go wrong. Option C quotes the source file correctly but leaves -o hello world unquoted. The shell sees hello as the output name and world as an additional (unexpected) source file argument, which breaks the compiler invocation entirely. Option D is the trickiest trap — everything looks fine until the very end. The executable path ./hello world is unquoted, so the shell interprets ./hello as the program and world as a command-line argument passed to it. If no file named hello exists, this fails; even if it did, it wouldn't run the intended program. Study tip: Treat spaces in filenames as a two-step checklist — quote the file and quote the output name. If either is missing quotes, the command will silently misbehave in ways that can be hard to debug.
  8. What happens as a result of this command?
    Answer: The compiler reports an error, and the existing a.out is not executed. When you see a command using && in a shell, the key concept being tested is short-circuit evaluation of shell operators. The && operator means "run the second command *only if the first command succeeds*" — success being defined as an exit code of zero. When g++ encounters a syntax error, it exits with a non-zero exit code (failure). Because the first command failed, the shell short-circuits and never runs ./a.out. This makes A the correct answer: the compiler reports the error, and the existing a.out is left completely untouched and unexecuted. B is tempting if you misunderstand && as a simple separator (like ;). A semicolon would run both commands regardless of outcome, but && is specifically conditional — the second command is gated on the first succeeding. So a.out never runs, and OLD is never printed. C is wrong on two counts: a compiler with a syntax error won't produce any output binary at all, and even if it somehow did, the && still wouldn't let execution reach ./a.out since the compiler exited with failure. D reverses the order of execution entirely. Shell commands in a pipeline execute left to right; the compiler always runs first, and ./a.out could only run after it — never before. A handy rule to lock this in: think of && as "and only then." If you want two commands to always run back-to-back regardless of errors, use ; instead. Knowing this distinction will help you on any question involving shell scripting or build automation.
  9. Which command compiles the source and then passes data.txt to the resulting program rather than to the compiler?
    Answer: g++ main.cpp -o runner && ./runner data.txt When working with command-line compilation, you need to mentally separate two distinct phases: compiling (what g++ does) and running (what the executable does). Arguments meant for your program must be passed to the executable, not to the compiler. The && operator chains commands sequentially — the right side only runs if the left side succeeds. In option C, g++ main.cpp -o runner compiles main.cpp and names the output runner. Then ./runner data.txt executes that binary with data.txt as its first argument, making it available as argv[1] inside main.cpp. This is exactly what the question requires. Option A places data.txt after -o runner in the g++ call, which tells the compiler to treat data.txt as an additional source file or input — not a runtime argument. The compiler will likely throw an error or ignore it. Option B also passes data.txt directly to g++ (before -o runner), suffering the same flaw: the compiler receives a file it doesn't know what to do with as a translation unit. Option D uses && data.txt as a standalone command after ./runner, which the shell interprets as trying to execute a file named data.txt as a program — that's not valid syntax for passing arguments. A useful habit: mentally draw a line between the compiler invocation and the program invocation. Everything left of && talks to g++; everything right of && talks to your program. Runtime arguments always belong on the run side, appended after the executable name.
  10. Which command sequence correctly completes the task?
    Answer: g++ -c main.cpp && g++ -c math.cpp && g++ main.o math.o -o calc && ./calc When working with multi-file C++ projects, you need to understand the two-stage build process: compilation (source files → object files) and linking (object files → executable). The -c flag tells g++ to compile only, producing .o object files without linking. The -o flag specifies the output filename. The && operator chains commands so each step runs only if the previous one succeeded — exactly what the question requires. A is correct because it follows the proper pipeline precisely. First, g++ -c main.cpp and g++ -c math.cpp compile each source file into main.o and math.o respectively. Then g++ main.o math.o -o calc links them into the executable calc. Finally, ./calc runs it — and each step is gated by &&, so failure at any point halts the chain. B omits the -c flag in the first two commands, meaning g++ will attempt a full compile-and-link on each file individually. This produces executables (not object files), so main.o and math.o won't exist when the linking step runs. C correctly compiles both files into object files, but then tries to execute the object files with ./main.o and ./math.o. Object files are not executables — they're intermediate binary blobs that must be linked first. D uses -o to name the output main.o and math.o, but without -c, g++ produces linked executables with those names, not true object files. The final ./calc also runs without ever being built. A helpful mental checklist: **compile with -c, link with -o executablename, run with ./name** — in that order.

Start this quiz