Introduction
One of the best ways to learn C programming is by working directly from the command line. While modern IDEs provide many conveniences, using the Terminal teaches you how programs are actually compiled, linked, and executed.
On a MacBook M1 (Apple Silicon), C development is built into macOS through Apple’s developer tools. The default compiler is Clang, which is part of the LLVM project.
This guide covers everything needed to write, compile, run, and debug C programs from the command line.
Step 1: Install the Command Line Tools
Open Terminal and type:
xcode-select --install
If already installed, you’ll see a message indicating so.
Verify installation:
clang --version
Example output:
Apple clang version 17.x.x
Target: arm64-apple-darwin
The “arm64” target indicates the compiler is producing native code for Apple Silicon.
Step 2: Create a Workspace
Create a directory for your C projects:
mkdir ~/c-projects
cd ~/c-projects
Verify:
pwd
Example:
/Users/yourname/c-projects
Step 3: Create Your First Program
Create a source file:
nano hello.c
Enter:
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
Save:
Control-O
Enter
Exit:
Control-X
Step 4: Compile the Program
Compile using Clang:
clang hello.c -o hello
Explanation:
clang = compiler
hello.c = source file
-o hello = output executable
You should see no output if compilation succeeds.
Step 5: Run the Program
Execute:
./hello
Output:
Hello, World!
The “./” tells the shell to execute a program from the current directory.
Understanding What Happened
The compiler performed several steps:
Source Code
↓
Preprocessor
↓
Compiler
↓
Assembler
↓
Linker
↓
Executable
The result is a native ARM64 executable that runs directly on your M1 processor.
Viewing Compiler Warnings
Always compile with warnings enabled:
clang -Wall -Wextra hello.c -o hello
Recommended for every project:
clang -Wall -Wextra -pedantic hello.c -o hello
Warnings often reveal bugs before they become problems.
Example: Variables
Create:
nano variables.c
Program:
#include <stdio.h>
int main(void)
{
int age = 55;
float temperature = 72.5;
printf("Age: %d\n", age);
printf("Temperature: %.1f\n", temperature);
return 0;
}
Compile:
clang -Wall -Wextra variables.c -o variables
Run:
./variables
Example: Loops
#include <stdio.h>
int main(void)
{
for(int i = 1; i <= 5; i++)
{
printf("%d\n", i);
}
return 0;
}
Compile:
clang loop.c -o loop
Run:
./loop
Output:
1
2
3
4
5
Example: Functions
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main(void)
{
int result = add(5, 7);
printf("%d\n", result);
return 0;
}
Compile:
clang functions.c -o functions
Run:
./functions
Example: Multiple Source Files
main.c
#include <stdio.h>
int add(int, int);
int main(void)
{
printf("%d\n", add(2, 3));
return 0;
}
math.c
int add(int a, int b)
{
return a + b;
}
Compile:
clang main.c math.c -o program
Run:
./program
This is how larger programs are organized.
Using Header Files
math.h
#ifndef MATH_H
#define MATH_H
int add(int a, int b);
#endif
math.c
#include "math.h"
int add(int a, int b)
{
return a + b;
}
main.c
#include <stdio.h>
#include "math.h"
int main(void)
{
printf("%d\n", add(10, 20));
return 0;
}
Compile:
clang main.c math.c -o program
Using Makefiles
Create:
nano Makefile
Contents:
CC=clang
CFLAGS=-Wall -Wextra
program: main.o math.o
$(CC) $(CFLAGS) main.o math.o -o program
main.o: main.c
$(CC) $(CFLAGS) -c main.c
math.o: math.c
$(CC) $(CFLAGS) -c math.c
clean:
rm -f *.o program
Build:
make
Clean:
make clean
Makefiles become essential for larger projects.
Debugging with LLDB
Compile with debugging symbols:
clang -g program.c -o program
Start debugger:
lldb ./program
Run:
run
Set breakpoint:
breakpoint set --name main
Inspect variables:
frame variable
Quit:
quit
LLDB is the macOS equivalent of GDB.
Viewing Assembly Code
Generate assembly:
clang -S hello.c
Produces:
hello.s
View:
cat hello.s
This shows the ARM64 instructions generated by the compiler.
Viewing Object Files
Compile only:
clang -c hello.c
Produces:
hello.o
Inspect:
file hello.o
Output:
Mach-O 64-bit object arm64
Mach-O is the executable format used by macOS.
Useful Terminal Commands
List files:
ls
Long listing:
ls -l
Current directory:
pwd
Create directory:
mkdir project
Change directory:
cd project
Remove file:
rm filename
Copy file:
cp source destination
Rename file:
mv oldname newname
Recommended Compile Command
For learning C:
clang -Wall -Wextra -pedantic -std=c17 program.c -o program
This enables:
- Strict standards compliance
- Helpful warnings
- Modern C language support
Conclusion
Writing C from the command line on a MacBook M1 teaches the fundamentals of software development. By learning how to create source files, compile programs, link multiple modules, use Makefiles, and debug with LLDB, you gain skills that transfer directly to Linux, FreeBSD, and other UNIX-like operating systems.
Many professional systems programmers still spend most of their time using the same tools:
- Terminal
- Clang or GCC
- Make
- LLDB or GDB
- Text editor
Mastering these tools provides a strong foundation for operating systems, networking, kernel development, and advanced UNIX programming.