Using the GNU C-Compiler (GCC)

Compiling and running a first C program

unsigned long result;

unsigned long factorial(unsigned long n)
{
    if (n>1) {
        return n*factorial(n-1);
    } else {
        return 1;
    }
}

int main()
{
    result = factorial(4);

    printf("result = %ld\n", result);

    return 0;
}

Compile (read but ignore the warning for the moment) and run the program with

$shell> gcc -Wall -std=c99 -o factorial factorial.c
factorial.c: In function 'main':
factorial.c:16:5: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
     printf("result = %ld\n", result);
     ^
factorial.c:16:5: warning: incompatible implicit declaration of built-in function 'printf'
factorial.c:16:5: note: include '' or provide a declaration of 'printf'
$shell> factorial
result = 24
$shell> 

Examine the generated assembly code

Check out the generated assembly code with

$shell> gcc -Wall -std=c99 -S -fomit-frame-pointer -fno-asynchronous-unwind-tables factorial.c
factorial.c: In function 'main':
factorial.c:16:5: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
     printf("result = %ld\n", result);
     ^
factorial.c:16:5: warning: incompatible implicit declaration of built-in function 'printf'
$shell> 

Note that the parameters -fomit-frame-pointer and -no-fasynchronous-unwind-tables are just used here for the sake of simplicity. The assembly code generated is stored in file factorial.s:

$shell> cat factorial.s
	.file	"factorial.c"
	.comm	result,8,8
	.text
	.globl	factorial
	.type	factorial, @function
factorial:
	subq	$24, %rsp
	movq	%rdi, 8(%rsp)
	cmpq	$1, 8(%rsp)
	jbe	.L2
	movq	8(%rsp), %rax
	subq	$1, %rax
	movq	%rax, %rdi
	call	factorial
	imulq	8(%rsp), %rax
	jmp	.L3
.L2:
	movl	$1, %eax
.L3:
	addq	$24, %rsp
	ret
	.size	factorial, .-factorial
	.section	.rodata
.LC0:
	.string	"result = %ld\n"
	.text
	.globl	main
	.type	main, @function
main:
	subq	$8, %rsp
	movl	$4, %edi
	call	factorial
	movq	%rax, result(%rip)
	movq	result(%rip), %rax
	movq	%rax, %rsi
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf
	movl	$0, %eax
	addq	$8, %rsp
	ret
	.size	main, .-main
	.ident	"GCC: (Debian 4.9.2-10) 4.9.2"
	.section	.note.GNU-stack,"",@progbits
$shell> 

Examine the result of the C Preprocessor (CPP)

Check the output of the CPP for the C program

#define N   6

unsigned long result;

unsigned long factorial(unsigned long n)
{
    if (n>1) {
        return n*factorial(n-1);
    } else {
        return 1;
    }
}

int main()
{
    result = factorial(N);

    printf("result = %ld\n", result);

    return 0;
}

Use the option -E so that gcc just calls the CPP and then stops (so any other options for gcc can be omitted):

$shell> gcc -E factorial2.c
# 1 "factorial2.c"
# 1 ""
# 1 ""
# 1 "factorial2.c"


unsigned long result;

unsigned long factorial(unsigned long n)
{
    if (n>1) {
        return n*factorial(n-1);
    } else {
        return 1;
    }
}

int main()
{
    result = factorial(6);

    printf("result = %ld\n", result);

    return 0;
}
$shell> 

Getting rid of the warning

#include <stdio.h>

#define N   6

unsigned long result;

unsigned long factorial(unsigned long n)
{
    if (n>1) {
        return n*factorial(n-1);
    } else {
        return 1;
    }
}

int main()
{
    result = factorial(N);

    printf("result = %ld\n", result);

    return 0;
}

Types size_t and ptrdiff_t