https://github.com/monadplus/learning-c
Introduction to C
https://github.com/monadplus/learning-c
Last synced: about 1 month ago
JSON representation
Introduction to C
- Host: GitHub
- URL: https://github.com/monadplus/learning-c
- Owner: monadplus
- Created: 2022-10-11T11:10:14.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2025-04-01T20:30:12.000Z (about 1 year ago)
- Last Synced: 2025-12-29T10:56:34.764Z (6 months ago)
- Language: C
- Size: 4.48 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.markdown
Awesome Lists containing this project
README
# Tutorial: C
Sources:
-
-
-
The GNU C Library:
## Compiling
Compiling `hello.c`:
```bash
$ gcc hello.c
$ ./a.out
```
## Types
Integer/Float Types:
| type | storage size | value range | precision |
| -------------- | ------------ | ------------------------------------------- | --------- |
| char | 1 byte | -128 to 127 or 0 to 255 | - |
| unsigned char | 1 byte | 0 to 255 | - |
| signed char | 1 byte | -128 to 127 | - |
| short | 2 bytes | -32,768 to 32,767 | - |
| unsigned short | 2 bytes | 0 to 65,535 | - |
| int | 4 bytes | -2,147,483,648 to 2,147,483,647 | - |
| unsigned int | 4 bytes | 0 to 4,294,967,295 | - |
| long | 8 bytes | -9223372036854775808 to 9223372036854775807 | - |
| unsigned long | 8 bytes | 0 to 18446744073709551615 | - |
| float | 4 bytes | 1.2E-38 to 3.4E+38 | 6 decimal places |
| double | 8 bytes | 2.3E-308 to 1.7E+308 | 15 decimal places |
| long double | 10 bytes | 3.4E-4932 to 1.1E+4932 | 19 decimal places |
Exact size use `sizeof(type)`:
```bash
# limits.h defines some ergonomic constants
$ gcc limits.c
```
Void type:
- void exit (int status);
- int rand(void);
- void *malloc( size_t size );
## Variables
```c
char c, ch;
int i,j, k;
double d;
float f = 3.0, f2 = 5.0;
byte z = 22;
```
Use `extern` to share variables between source files.
## Constants and Literals
Literals:
```c
// Integer literals
85 // decimal
0213 // octal
0x4b // hexadecimal
30 // int
30u // unsigned int
30l // long
30ul // unsigned long
// Floating ponts
3.14159
314159E-5L
// Character constants
'x'
'\t'
'\u02C0'
```
Constants:
```c
#define LENGTH 50 // Preprocessor
const int LENGTH = 50; // const keyword
```
## Storage Classes
scope and life-time of variables and/or functions:
- auto
- register
- static
- extern
__auto__ (default): functions and local variables.
```c
int mount; // auto
auto int month; // auto
```
__register__: stored in a register, max size = 1 WORD, and can't have the & operator applied (it does not have a memory location).
```c
register int miles; // register
```
__static__:
- local variables: keep the value between functions calls.
- global variables: restrict the scope to the file.
```c
static int count = 5; // static
```
__extern__: global variable visible to all the program files.
```c
// compile: $gcc main.c support.c
// main.c
#include
int count ;
extern void write_extern();
main() {
count = 5;
write_extern();
}
// support.c
#include
extern int count;
void write_extern(void) {
printf("count is %d\n", count);
}
```
## Operators
```c
modulus: %
// bitwise
bitwise and: p & q
bitwise or: p | q
bitwise xor: p ^ q
bitwise complement: ~p
bitwise left shift: <<
bitwise right shift: >>
// assignment operators
+=
-=
*=
/=
%=
<<=
>>=
&=
|=
^=
// Misc
sizeof()
&a; // address
*a; // pointer
b ? a : b // conditional operator
```
## Loops
while loop:
```c
while(condition) {
statement(s);
}
```
for loop:
```c
for ( init; condition; increment ) {
statement(s);
}
```
do while loop:
```c
do {
statement(s);
} while( condition );
```
Infinite loop:
```c
for( ; ; ) {
printf("This loop will run forever.\n");
}
```
loop control statement:
```c
break // terminate the loop
continue // go to next iteration
goto
LOOP:do {
if( a == 15) {
goto LOOP;
}
printf("value of a: %d\n", a);
a++;
}while( a < 20 );
```
## Functions
```c
int max(int x, int y) {
return (x <= y) ? y : x;
}
```
Call by value: copies the actual value of the arguments
```c
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
return;
}
int a = 100;
int b = 200;
swap(a, b);
// a = 100
// b = 200
```
Call by reference:
```c
void swap(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
return;
}
int a = 100;
int b = 200;
swap(&a, &b);
// a = 200
// b = 100
```
## Scope Rules
- local
- global
- formal: function arguments, they take precedence over global variables.
## Arrays
```c
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
double salary = balance[0];
int matrix[10][10];
int matrix[3][2] = { {0,1}, {2,3}, {4,5} };
int a = matrix[0][0];
```
### Passing arrays as function arguments
```c
void myFunction(int *param) {..}
void myFunction(int param[10]) {..}
void myFunction(int param[]) {..}
```
```c
double average(int arr[], int size) {
double sum = 0;
for(i = 0; i < size; ++i){
sum += arr[i]
}
int avg = sum / size;
return avg;
}
int main () {
int balance[5] = {1, 2, 3, 4, 5}
double avg = average(balance, 5);
}
```
### Return array from function in C
The local variable that you are going to return __must__ be declared static.
```c
#include
int * getRandom( ) {
static int r[10];
int i;
srand( (unsigned)time( NULL ) );/* set the seed */
for ( i = 0; i < 10; ++i) {
r[i] = rand();
}
return r;
}
int main () {
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ ) {
printf( "*(p + %d) : %d\n", i, *(p + i));
}
return 0;
}
```
### Pointer to an Array in C
An array name is a constant pointer to the first element of the array.
For example, `double balance[50];` balance points to `&balance[0]`:
```c
double *p;
double balance[10];
p = balance;
p[0];
*(balance + 1);
```
## Pointers
```c
int *ip; /* pointer to an integer */
double *dp; /* pointer to a double */
float *fp; /* pointer to a float */
char *ch /* pointer to a character */
```
```c
int var = 20; // &var = bffd8b3c
int *ip = NULL; // NULL = 0 address
ip = &var;
ip // bffd8b3c = &var
*ip // 20
if (ptr) // succeeds if p is not null
if (!ptr) // succeeds if p is null
```
### Arithmetic operations
```c
#include
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr;
ptr = var;
for ( i = 0; i < MAX; i++) {
ptr++;
}
while ( ptr <= &var[MAX - 1] ) {
ptr--;
}
return 0;
}
```
### Array of pointers
```c
#include
const int MAX = 3;
int main () {
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++) {
ptr[i] = &var[i];
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
```
```c
char *names[] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali"
};
int i = 0;
for ( i = 0; i < MAX; i++) {
printf("Value of names[%d] = %s\n", i, names[i] );
}
```
### Passing pointers to functions
```c
#include
#include
void getSeconds(unsigned long *par);
int main () {
unsigned long sec;
getSeconds( &sec );
return 0;
}
void getSeconds(unsigned long *par) {
*par = time( NULL );
return;
}
```
```c
#include
double getAverage(int *arr, int size);
int main () {
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
avg = getAverage( balance, 5 ) ;
return 0;
}
double getAverage(int *arr, int size) {
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i) {
sum += arr[i];
}
avg = (double)sum / size;
return avg;
}
```
### Returning pointers from functions
See [return array from function in C](#return-array-from-function-in-c)
### Passing functions as function parameters
```c
#include
void print(int x);
void func(void (*f)(int));
void print ( int x ) {
printf("%d\n", x);
}
void func ( void (*f)(int) ) {
for ( int ctr = 0 ; ctr < 5 ; ctr++ ) {
(*f)(ctr);
}
}
int main() {
func(print);
return 0;
}
```
## Strings
```c
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char greeting[] = "Hello";
```
```c
strcpy(s1,s2); // copies string s2 into string s1
strcat(s1, s2); // concatenates s1 ++ s2
strlen(s1);
strcmp(s1,s2); // < 0 if s1 < s2
// 0 if s1 == s2
// > 0 if s1 > s2
strchr(s1, ch); // returns a pointer to the first occurrence of 'ch' in s1.
strstr(s1, s2); // returns a pointer to the first occurence of string s2 in string s1.
```
```c
#include
#include
int main () {
char str1[12] = "Hello";
char str2[12] = "World";
char str3[12];
int len ;
/* copy str1 into str3 */
strcpy(str3, str1);
printf("strcpy( str3, str1) : %s\n", str3 );
/* concatenates str1 and str2 */
strcat( str1, str2);
printf("strcat( str1, str2): %s\n", str1 );
/* total lenghth of str1 after concatenation */
len = strlen(str1);
printf("strlen(str1) : %d\n", len );
return 0;
}
```
## Structures
```c
#include
#include
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
void printBook( struct Books book );
void printBook2( struct Books *book );
int main( ) {
struct Books Book1;
struct Books Book2;
strcpy( Book1.title, "C Programming");
strcpy( Book1.author, "Nuha Ali");
strcpy( Book1.subject, "C Programming Tutorial");
Book1.book_id = 6495407;
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Zara Ali");
strcpy( Book2.subject, "Telecom Billing Tutorial");
Book2.book_id = 6495700;
printf( "Book 1 title : %s\n", Book1.title);
printf( "Book 1 author : %s\n", Book1.author);
printf( "Book 1 subject : %s\n", Book1.subject);
printf( "Book 1 book_id : %d\n", Book1.book_id);
printf( "Book 2 title : %s\n", Book2.title);
printf( "Book 2 author : %s\n", Book2.author);
printf( "Book 2 subject : %s\n", Book2.subject);
printf( "Book 2 book_id : %d\n", Book2.book_id);
printBook( Book1 );
printBook2( &Book1 );
return 0;
}
void printBook( struct Books book ) {
printf( "Book title : %s\n", book.title);
printf( "Book author : %s\n", book.author);
printf( "Book subject : %s\n", book.subject);
printf( "Book book_id : %d\n", book.book_id);
}
void printBook2( struct Books *book ) {
printf( "Book title : %s\n", book->title);
printf( "Book author : %s\n", book->author);
printf( "Book subject : %s\n", book->subject);
printf( "Book book_id : %d\n", book->book_id);
}
```
## Unions
Store different data types in the same memory location.
```c
#include
#include
union Data {
int i;
float f;
char str[20];
};
int main( ) {
union Data data;
printf( "Memory size occupied by data : %d\n", sizeof(data)); // 20
data.i = 10;
data.f = 220.5;
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i); // data.i : 1917853763
printf( "data.f : %f\n", data.f); // data.f : 4122360580327794860452759994368.000000
printf( "data.str : %s\n", data.str); // data.str : C Programming
return 0;
}
```
## Bit Fields
You can at most use 1 bit for each variable.
The minimum size is a WORD.
```c
#include
#include
// Requires 8 bytes
struct {
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
// Requires 4 bytes, only 2 bits are used.
struct {
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( ) {
printf( "Memory size occupied by status1 : %d\n", sizeof(status1)); // Memory size occupied by status1 : 8
printf( "Memory size occupied by status2 : %d\n", sizeof(status2)); // Memory size occupied by status2 : 4
return 0;
}
```
If you will use up to 32 variables each one with a width of 1 bit, then also the status structure will use 4 bytes.
If you try to use more bits than the requested you are going to do a no-op.
## Typedef
Type alias `typedef unsigned char BYTE;`.
```c
#include
#include
typedef struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
#define TRUE 1
#define FALSE 0
int main( ) {
Book book; // no need to write struct.
// works the same way.
printf("Value of True: %d\n", TRUE);
return 0;
}
```
### typedef vs #define
`typedef` can only be used for type aliases, `#define` can be used for more things.
`typedef` is interpreted by the compiler whereas `#define` is processed by the pre-processor.
## Input & Output
```c
int getchar(void); // returns the next available character from the stdin
int putchar(int c);
```
```c
char *gets(char *s); // deprecated in favor of fgets()
int puts(const char *s);
// Example
#include
int main( ) {
char str[100];
printf( "Enter a value :");
gets( str );
printf( "\nYou entered: ");
puts( str );
return 0;
}
```
```c
int scanf(const char *format, ...)
int printf(const char *format, ...)
// Example
#include
int main( ) {
char str[100];
int i;
scanf("%s %d", str, &i);
printf( "\nYou entered: %s %d ", str, i);
return 0;
}
```
## File I/O
### Open/Close
```c
// mode (you can combine them e.g. rb, wb, rb+):
// r read
// w write (if it does not exist, creates a new file)
// a append (if it does not exist, creates a new file)
// r+ read+write
// w+ read+write. Truncates the file to 0 (if it does not exist, creates a new file)
// a+ read+wite. read from start, write appending (if it does not exist, creates a new file)
FILE *fopen( const char * filename, const char * mode );
int fclose( FILE *fp );
```
### Writing
```c
int fputc( int c, FILE *fp ); // single char
int fputs( const char *s, FILE *fp ); // string
int fprintf(FILE *fp,const char *format, ...) // similar to fputs
//Example
#include
main() {
FILE *fp;
fp = fopen("/tmp/test.txt", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
fclose(fp);
}
```
### Reading
```c
int fgetc( FILE * fp ); // Char
char *fgets( char *buf, int n, FILE *fp ); // appends a null character aat the end of buf.
// stops when it encounters a '\n' or EOF or reads n characters.
int fscanf(FILE *fp, const char *format, ...)
//Example
#include
main() {
FILE *fp;
char buff[255];
fp = fopen("/tmp/test.txt", "r");
fscanf(fp, "%s", buff);
printf("1 : %s\n", buff );
fgets(buff, 255, (FILE*)fp);
printf("2: %s\n", buff );
fgets(buff, 255, (FILE*)fp);
printf("3: %s\n", buff );
fclose(fp);
}
```
### Binary I/O Functions
```c
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
```
## Preprocessors
CPP (C preprocessor) is a separate state in the compilation process.
```c
#define Substitutes a preprocessor macro.
#include Inserts a particular header from another file.
#undef Undefined a preprocessor macro.
#ifdef Returns true if this macro is defined.
#ifndef Returns true if this macro is not defined.
#if Test if a compiler time condition is true.
#else
#elif
#endif
#error Prints error message on stderr.
#pragma Issues special commands to the compiler, using a standardized method.
// Examples
#define MAX_ARRAY_LENGTH 20
#include
#include "myheader.h"
#undef FILE_SIZE
#define FILE_SIZE 42
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
#ifdef DEBUG
#error "DEBUG MODE"
#endif
```
### Predefined macros
```c
#include
int main() {
printf("File :%s\n", __FILE__ ); // File :test.c
printf("Date :%s\n", __DATE__ ); // Date :Jun 2 2012
printf("Time :%s\n", __TIME__ ); // Time :03:36:24
printf("Line :%d\n", __LINE__ ); // Line :8
printf("ANSI :%d\n", __STDC__ ); // ANSI :1
}
```
### Preprocessor Operators
The Macro Continuation (\) Operator
The Stringize (#) Operator
```c
#include
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra); // Carole and Debra: We love you!
return 0;
}
```
The Token Pasting (##) Operator
```c
#include
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
// Replaced by:
// printf ("token34 = %d", token34);
tokenpaster(34); // Outputs: token34 = 40
return 0;
}
```
The Defined() Operator
```c
#include
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
```
Parameterized Macros
The definition will be __inlined__.
```c
#include
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
```
## Header Files
File with extension __.h__ which contains function declarations and macro definitions to be shared.
The compiler comes with some header files.
```c
#include // System headers files. You can add directories using -l
#include "file" // Only in the current directory. You can add directories using -l
```
The preprocessors copies the source of the header file into your program.
Prevent copying the header file multiple types.
```c
#ifndef STDIO
#define STDIO
#include
#endif
```
## Type Casting
Cast operator: `mean = (double) sum / count;`
## Error Handling
Error codes defined in .
errno, perror(), and strerror()
```c
#include
#include
#include
extern int errno ;
int main () {
FILE * pf;
int errnum;
pf = fopen ("unexist.txt", "rb");
if (pf == NULL) {
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno); // Value of errno: 2
perror("Error printed by perror"); // Error printed by perror: No such file or directory
fprintf(stderr, "Error opening file: %s\n", strerror( errnum )); // Error opening file: No such file or directory
} else {
fclose (pf);
}
return 0;
}
```
## Variable Arguments
```c
#include
#include // required for variadic arguments
double average(int num,...) {
va_list valist;
double sum = 0.0;
int i;
/* initialize valist for num number of arguments */
va_start(valist, num);
/* access all the arguments assigned to valist */
for (i = 0; i < num; i++) {
sum += va_arg(valist, int);
}
/* clean memory reserved for valist */
va_end(valist);
return sum/num;
}
int main() {
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}
```
## Memory Management
From ``:
```c
void *calloc(int num, int size); // num * size bytes
void free(void *address);
void *malloc(int num); // num bytes
void *realloc(void *address, int newsize); // extens allocated memory up to newsize.
```
```c
#include
#include
#include
int main() {
char name[100];
char *description;
strcpy(name, "Zara Ali");
description = malloc( 200 * sizeof(char) );
if( description == NULL ) {
fprintf(stderr, "Error - unable to allocate required memory\n");
} else {
strcpy( description, "Zara ali a DPS student in class 10th");
}
printf("Name = %s\n", name );
printf("Description: %s\n", description ); // Description: Zara ali a DPS student in class 10th
}
```
## Command Line Arguments
```bash
$./a.out testing
The argument supplied is testing
```
```c
#include
// argv[0] = name of the program
// argv[1] pointer to the first command line argument.
int main( int argc, char *argv[] ) {
if( argc == 2 ) {
printf("The argument supplied is %s\n", argv[1]);
}
else if( argc > 2 ) {
printf("Too many arguments supplied.\n");
}
else {
printf("One argument expected.\n");
}
}
```
# Tutorial: GCC and Make
## GCC
Source:
The GNU C Compiler (GCC). Current version 8.3.0
```bash
# 1.
$ gcc -Wall -g source1.c source2.c -o program_name
-g: debug
-v: verbose
-Dname: defining macros. Example -DDEBUG="TRUE", -DHaskell="Haskell 98"
# 2. Compile and then link
$ gcc -c -Wall hello.c
$ gcc -c -Wall util.c
$ gcc hello.o util.o -o hello
# Shared library .so
Compile using -shared
```
### GCC Compilation Process
```
Source (.c, .h)
Preprocessing (cpp)
Include Header, Expand Macro (.i)
Compilation (gcc)
Assembly Code (.s)
Assemble (as)
Machine Code (.o)
Linking (ld)
Static Library (.a)
Executable Machine Code
```
GCC compiles the program in the four previous steps:
```bash
# Pre-processing
$ cpp hello.c > hello.i
# Compilation
$ gcc -S hello.i
# Assembly
$ as -o hello.o hello.s
# Linker
$ ld -o hello hello.o ..libraries...
```
### Headers (.h), Static Libraries (.a) and Shared Libraries (.a)
#### Static vs Shared
A library is a collection of pre-compiled object files that can be linked into your programs via the linker.
Static (.a): the code is copied into the executable.
Dynamic (.so): only a small table of references is copied. Before the executable is run, the OS loads the machine code needed for the external functions (dynamic linking).
#### Searching for Header Files and Libraries (-I, -L and -l)
The __compiler__ needs the __headers file__ to compile the code.
The __linker__ needs the __libraries__ to resolve external references from other object files or libraries.
For headers: gcc option `-Idir` or `CPATH` environment variable.
For librares: `-Ldir` or `LIBRARY_PATH`. In addition, you also have to specify the library name: `-lxxx.a`.
The are some default paths:
```bash
$ gcc -v -o hello hello.c
# -L/usr/lib/gcc/x86_64-pc-cygwin/6.4.0
# -L/usr/x86_64-pc-cygwin/lib
# -L/usr/lib
# -L/lib
# -lgcc_s // libgcc_s.a
# -lgcc // libgcc.a
# -lcygwin // libcygwin.a
# -ladvapi32 // libadvapi32.a
# -lshell32 // libshell32.a
# -luser32 // libuser32.a
# -lkernel32 // libkernel32.a
```
#### Utilities for examining the compiled files
```bash
# File type
$ file
# List symbol table of object files
$ nm hello.o
# List Dynamic-Link Libraries
$ ldd hello
```
## Make
Automate compilation.
```make
# Makefile
CC = gcc -Wall
all: hello
# Checks if hello.o exists, otherwise looks for a rule to create it.
hello: hello.o
$(CC) -o hello hello.o
hello.o: hello.c
$(CC) -c hello.c
clean:
rm hello.o hello
```
### Automatic variables
```
$@: the target filename.
$*: the target filename without the file extension.
$<: the first prerequisite filename.
$^: the filenames of all the prerequisites, separated by spaces, discard duplicates.
$+: similar to $^, but includes duplicates.
$?: the names of all prerequisites that are newer than the target, separated by spaces.
```
Example:
```make
all: hello
# $@ matches the target; $< matches the first dependent
hello: hello.o
gcc -o $@ $<
hello.o: hello.c
gcc -c $<
clean:
rm hello.o hello
```
### Virtual Path (VPATH)
```make
# Search for dependencies and targets from "src" and "include" directories
# The directories are separated by space
VPATH = src include
```
### Pattern Rules
```make
# Applicable for create .o object file.
# '%' matches filename.
# $< is the first pre-requisite
# $(COMPILE.c) consists of compiler name and compiler options
# $(OUTPUT_OPTIONS) could be -o $@
%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
# Applicable for create executable (without extension) from object .o object file
# $^ matches all the pre-requisites (no duplicates)
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
```
### A sample Makefile
```make
# A sample Makefile
# This Makefile demonstrates and explains
# Make Macros, Macro Expansions,
# Rules, Targets, Dependencies, Commands, Goals
# Artificial Targets, Pattern Rule, Dependency Rule.
# Comments start with a # and go to the end of the line.
# Here is a simple Make Macro.
LINK_TARGET = test_me.exe
# Here is a Make Macro that uses the backslash to extend to multiple lines.
OBJS = \
Test1.o \
Test2.o \
Main.o
# Here is a Make Macro defined by two Macro Expansions.
# A Macro Expansion may be treated as a textual replacement of the Make Macro.
# Macro Expansions are introduced with $ and enclosed in (parentheses).
REBUILDABLES = $(OBJS) $(LINK_TARGET)
# Here is a simple Rule (used for "cleaning" your build environment).
# It has a Target named "clean" (left of the colon ":" on the first line),
# no Dependencies (right of the colon),
# and two Commands (indented by tabs on the lines that follow).
# The space before the colon is not required but added here for clarity.
clean :
rm -f $(REBUILDABLES)
echo Clean done
# There are two standard Targets your Makefile should probably have:
# "all" and "clean", because they are often command-line Goals.
# Also, these are both typically Artificial Targets, because they don't typically
# correspond to real files named "all" or "clean".
# The rule for "all" is used to incrementally build your system.
# It does this by expressing a dependency on the results of that system,
# which in turn have their own rules and dependencies.
all : $(LINK_TARGET)
echo All done
# There is no required order to the list of rules as they appear in the Makefile.
# Make will build its own dependency tree and only execute each rule only once
# its dependencies' rules have been executed successfully.
# Here is a Rule that uses some built-in Make Macros in its command:
# $@ expands to the rule's target, in this case "test_me.exe".
# $^ expands to the rule's dependencies, in this case the three files
# main.o, test1.o, and test2.o.
$(LINK_TARGET) : $(OBJS)
g++ -g -o $@ $^
# Here is a Pattern Rule, often used for compile-line.
# It says how to create a file with a .o suffix, given a file with a .cpp suffix.
# The rule's command uses some built-in Make Macros:
# $@ for the pattern-matched target
# $< for the pattern-matched dependency
%.o : %.cpp
g++ -g -o $@ -c $<
# These are Dependency Rules, which are rules without any command.
# Dependency Rules indicate that if any file to the right of the colon changes,
# the target to the left of the colon should be considered out-of-date.
# The commands for making an out-of-date target up-to-date may be found elsewhere
# (in this case, by the Pattern Rule above).
# Dependency Rules are often used to capture header file dependencies.
Main.o : Main.h Test1.h Test2.h
Test1.o : Test1.h Test2.h
Test2.o : Test2.h
# Alternatively to manually capturing dependencies, several automated
# dependency generators exist. Here is one possibility (commented out)...
# %.dep : %.cpp
# g++ -M $(FLAGS) $< > $@
# include $(OBJS:.o=.dep)
```