Course outline

C / Basic: Read and Construct Programs / Lesson 1

The Toolchain and the C Program Model

Follow source text through translation and execution, and separate language rules from tool and platform choices.

About 5 min readContent reviewed
On this page

Lesson goals

  • Identify preprocessing, compilation, assembly, and linking.
  • Explain hosted main, library declarations, and observable output.
  • Select C17 and interpret diagnostics in context.

Source files become a program

C source describes objects, functions, and operations; it is not a transcript of processor instructions. A translation unit is a source file after preprocessing, including the text brought in by headers. The implementation translates units and combines the required definitions and libraries. Thinking in units explains why a declaration can be visible while its function definition is missing at link time.

A common toolchain exposes preprocessing, compilation, assembly, and linking as separate stages. ISO C specifies translation behavior without requiring these to be separate command-line programs. A successful compiler invocation establishes neither correct business logic nor freedom from every runtime error.

Entry, declarations, and effects

In a hosted program, int main(void) is a standard entry form. stdio.h declares puts, allowing the compiler to check its call. The literal contains the displayed characters; puts adds the newline. Returning zero reports successful termination to the host environment. The host may interpret other status values using its own documented conventions.

C and C++ are different languages. Compile this file as C, keep the .c suffix, and avoid importing advice about cout, new, references, or classes. The small example already illustrates a contract: library declarations describe allowed calls, and the implementation supplies their behavior.

c A complete hosted program
#include <stdio.h>

int main(void)
{
    puts("C program ready");
    return 0;
}
Expected output
C program ready

The header supplies the declaration; puts writes one line, and main reports success.

Choose a reproducible language mode

An explicit command such as cc -std=c17 -Wall -Wextra -Wpedantic hello.c -o hello records the intended language and useful warnings. These options belong to GCC-compatible tools, not to the C grammar. The executable name and the command used to launch it depend on the development environment. Keep the source and the command together when asking someone to reproduce a result.

Compiler defaults change across releases. Selecting C17 avoids accidentally accepting a newer construct or a GNU extension as course baseline behavior. Warnings are evidence to investigate, not proof that every accepted program is portable. Start with the earliest diagnostic because later messages can follow from the first error.

Trace changes to objects

An object is a region of storage representing a value of a type. Here count starts at two, the next statement replaces its stored value with five, and printf observes that value. The assignment is an operation, not an assertion of mathematical equality. Each full statement completes before the following full statement begins in this simple single-threaded execution.

A trace table can list the value after each statement and the text written at each output call. This is more reliable than imagining memory addresses or processor registers. The abstract machine lets us explain the result without claiming that every source variable occupies a physical stack slot.

c Observe a stored value
#include <stdio.h>

int main(void)
{
    int count = 2;
    count = count + 3;
    printf("count=%d\n", count);
    return 0;
}
Expected output
count=5

%d matches int. The separate assignment finishes before printf reads count.

Distinguish kinds of evidence

A syntax error prevents translation; an unresolved symbol usually appears during linking; a wrong answer is a runtime logic failure. A crash is only one possible symptom of invalid C. Some mistakes cause undefined behavior, for which the language supplies no required result. Observing one run therefore cannot establish a portable output for an invalid program.

Keep a small notebook containing the compiler version, language mode, input, expected output, and actual output. When a result surprises you, reduce the program while preserving the failure. That discipline turns vague reports into checkable claims and prepares you for the testing and debugging tools introduced later.

Common errors and fixes

The linker cannot find a function.

Why it happens
A declaration was included, but its definition or required object file was omitted.
How to fix it
Link the translation unit or documented library containing the definition.
Prevent it next time
Record every build input and distinguish a declaration from a definition.

The source compiles only as C++.

Why it happens
The file or driver selects a different language.
How to fix it
Use a .c file and a C driver with an explicit C17 mode.
Prevent it next time
Check the actual invocation before comparing language rules.

An old executable appears to ignore an edit.

Why it happens
The build failed or produced an executable at another path.
How to fix it
Resolve diagnostics, confirm the output path, and rebuild successfully.
Prevent it next time
Run only the executable associated with the recorded successful build.

Check your understanding

1. Predict the trace if count starts at four and the assignment adds seven. Explain what changes in the source.

Show worked solution

Replace the initializer 2 with 4 and the added constant 3 with 7. After initialization count is 4; after assignment it is 11; printf writes count=11 followed by a newline. The type and format remain int and %d. No address or architecture assumption is needed.

2. A build reports an undeclared puts, then several later errors. Describe the first investigation and a reproducible report.

Show worked solution

Check whether stdio.h is included before the call and whether preprocessing selected the expected source. Fix the earliest relevant diagnostic and rebuild before chasing later messages. Report the complete short source, compiler version, exact C17 command, and diagnostic text. Do not hide the missing declaration with an invented prototype.

Key takeaways

  • A program is translated and linked before its runtime behavior can be observed.
  • Choose the language mode explicitly and treat diagnostics as evidence.
  • A successful run demonstrates that run; language contracts justify portable reasoning.

Official references