Understand your first C "Hello World" Program!

Understand your first C "Hello World" Program!

Usually, we learn the first program in any language as the “Hello World” program. This is probably the first program people write while starting a coding journey.
Let’s deep dive into below C code.

/* Writing the first C Program */

#include <stdio.h>
int main()
{
    printf("Hello World");
    return 0;
}

Let’s understand how this piece of shit can be converted to the program. The above written lines are just pieces of information and it’s each line is meaningful.

Header and Preprocessing

/*header file inclusion.*/

#include <stdio.h>

The first step of compilation. The line that starts with # indicates that it’s C preprocessors that do nothing but substitute the actual piece of code. If you really want to see how will it look originally then you can try running the below command.

$gcc -E helloworld.c

1 "helloworld.c"
1 ""
1 ""
31 ""
1 "/usr/include/stdc-predef.h" 1 3 4
32 "" 2
1 "helloworld.c"
1 "/usr/include/stdio.h" 1 3 4
27 "/usr/include/stdio.h" 3 4
1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
1 "/usr/include/features.h" 1 3 4
461 "/usr/include/features.h" 3 4
1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
452 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
453 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
454 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
462 "/usr/include/features.h" 2 3 4
485 "/usr/include/features.h" 3 4
1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
486 "/usr/include/features.h" 2 3 4
34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
28 "/usr/include/stdio.h" 2 3 4
1 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 1 3 4
209 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 3 4
209 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stddef.h" 3 4
typedef long unsigned int size_t;
34 "/usr/include/stdio.h" 2 3 4
1 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stdarg.h" 1 3 4
40 "/usr/lib/gcc/x86_64-linux-gnu/9/include/stdarg.h" 3 4
typedef __builtin_va_list __gnuc_va_list;
37 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4
27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
28 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/timesize.h" 1 3 4
29 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
typedef unsigned char __u_char;

typedef unsigned short int __u_short;

typedef unsigned int __u_int;

typedef unsigned long int __u_long;
typedef signed char __int8_t;

typedef unsigned char __uint8_t;

typedef signed short int __int16_t;

typedef unsigned short int __uint16_t;

typedef signed int __int32_t;

typedef unsigned int __uint32_t;
typedef signed long int __int64_t;

typedef unsigned long int __uint64_t;
typedef __int8_t __int_least8_t;

typedef __uint8_t __uint_least8_t;

typedef __int16_t __int_least16_t;

typedef __uint16_t __uint_least16_t;

typedef __int32_t __int_least32_t;

typedef __uint32_t __uint_least32_t;

typedef __int64_t __int_least64_t;

typedef __uint64_t __uint_least64_t;
typedef long int __quad_t;

typedef unsigned long int __u_quad_t;
typedef long int __intmax_t;

typedef unsigned long int __uintmax_t;
141 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
1 "/usr/include/x86_64-linux-gnu/bits/typesizes.h" 1 3 4
142 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/time64.h" 1 3 4
143 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4
typedef unsigned long int __dev_t;

typedef unsigned int __uid_t;

typedef unsigned int __gid_t;

typedef unsigned long int __ino_t;

typedef unsigned long int __ino64_t;

typedef unsigned int __mode_t;

typedef unsigned long int __nlink_t;

typedef long int __off_t;

typedef long int __off64_t;

typedef int __pid_t;

typedef struct { int __val[2]; } __fsid_t;

typedef long int __clock_t;

typedef unsigned long int __rlim_t;

typedef unsigned long int __rlim64_t;

typedef unsigned int __id_t;

typedef long int __time_t;

typedef unsigned int __useconds_t;

typedef long int __suseconds_t;
typedef int __daddr_t;

typedef int __key_t;
typedef int __clockid_t;
typedef void * __timer_t;
typedef long int __blksize_t;
typedef long int __blkcnt_t;

typedef long int __blkcnt64_t;
typedef unsigned long int __fsblkcnt_t;

typedef unsigned long int __fsblkcnt64_t;
typedef unsigned long int __fsfilcnt_t;

typedef unsigned long int __fsfilcnt64_t;
typedef long int __fsword_t;
typedef long int __ssize_t;
typedef long int __syscall_slong_t;
typedef unsigned long int __syscall_ulong_t;
typedef __off64_t __loff_t;

typedef char *__caddr_t;
typedef long int __intptr_t;
typedef unsigned int __socklen_t;
typedef int __sig_atomic_t;
39 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 1 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 1 3 4
13 "/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h" 3 4
typedef struct

{

int __count;

union

{

unsigned int __wch;

char __wchb[4];

} __value;

} __mbstate_t;
6 "/usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h" 2 3 4
typedef struct _G_fpos_t

{

__off_t __pos;

__mbstate_t __state;

} __fpos_t;
40 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 1 3 4
10 "/usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h" 3 4
typedef struct _G_fpos64_t

{

__off64_t __pos;

__mbstate_t __state;

} __fpos64_t;
41 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/__FILE.h" 1 3 4
struct _IO_FILE;

typedef struct _IO_FILE __FILE;
42 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/FILE.h" 1 3 4
struct _IO_FILE;
typedef struct _IO_FILE FILE;
43 "/usr/include/stdio.h" 2 3 4
1 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 1 3 4
35 "/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h" 3 4
struct _IO_FILE;

struct _IO_marker;

struct _IO_codecvt;

struct _IO_wide_data;
typedef void _IO_lock_t;
struct _IO_FILE

{

int _flags;
char *_IO_read_ptr;

char *_IO_read_end;

char *_IO_read_base;

char *_IO_write_base;

char *_IO_write_ptr;

char *_IO_write_end;

char *_IO_buf_base;

char *_IO_buf_end;
char *_IO_save_base;

char *_IO_backup_base;

char *_IO_save_end;
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;

int _flags2;

__off_t _old_offset;
unsigned short _cur_column;

signed char _vtable_offset;

char _shortbuf[1];
_IO_lock_t *_lock;
__off64_t _offset;
struct _IO_codecvt *_codecvt;

struct _IO_wide_data *_wide_data;

struct _IO_FILE *_freeres_list;

void *_freeres_buf;

size_t __pad5;

int _mode;
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];

};
44 "/usr/include/stdio.h" 2 3 4
52 "/usr/include/stdio.h" 3 4
typedef __gnuc_va_list va_list;
63 "/usr/include/stdio.h" 3 4
typedef __off_t off_t;
77 "/usr/include/stdio.h" 3 4
typedef __ssize_t ssize_t;
typedef __fpos_t fpos_t;
133 "/usr/include/stdio.h" 3 4
1 "/usr/include/x86_64-linux-gnu/bits/stdio_lim.h" 1 3 4
134 "/usr/include/stdio.h" 2 3 4
extern FILE *stdin;

extern FILE *stdout;

extern FILE *stderr;
extern int remove (const char *filename) __attribute ((nothrow , leaf));
extern int rename (const char *old, const char *__new) __attribute ((nothrow , leaf));
extern int renameat (int oldfd, const char *__old, int __newfd,
const char *__new) __attribute ((nothrow , leaf));
173 "/usr/include/stdio.h" 3 4
extern FILE *tmpfile (void) ;
187 "/usr/include/stdio.h" 3 4
extern char *tmpnam (char *s) __attribute ((nothrow , leaf)) ;
extern char *tmpnam_r (char *s) __attribute ((nothrow , leaf)) ;
204 "/usr/include/stdio.h" 3 4
extern char *tempnam (const char *dir, const char *__pfx)
__attribute ((nothrow , leaf)) attribute ((malloc)) ;
extern int fclose (FILE *__stream);
extern int fflush (FILE *__stream);
227 "/usr/include/stdio.h" 3 4
extern int fflush_unlocked (FILE *__stream);
246 "/usr/include/stdio.h" 3 4
extern FILE *fopen (const char *__restrict __filename,

const char *__restrict __modes) ;

extern FILE *freopen (const char *__restrict __filename,

const char *__restrict __modes,

FILE *__restrict __stream) ;

279 "/usr/include/stdio.h" 3 4
extern FILE *fdopen (int fd, const char *__modes) __attribute ((nothrow , leaf)) ;
292 "/usr/include/stdio.h" 3 4
extern FILE *fmemopen (void *s, size_t __len, const char *__modes)
__attribute ((nothrow , leaf)) ;
extern FILE *open_memstream (char **bufloc, size_t *__sizeloc) __attribute ((nothrow , leaf)) ;
extern void setbuf (FILE *restrict __stream, char *__restrict __buf) __attribute ((nothrow , leaf));
extern int setvbuf (FILE *restrict __stream, char *__restrict __buf,
int __modes, size_t __n) __attribute ((nothrow , leaf));
extern void setbuffer (FILE *restrict __stream, char *__restrict __buf,
size_t __size) __attribute ((nothrow , leaf));
extern void setlinebuf (FILE *stream) __attribute ((nothrow , leaf));
extern int fprintf (FILE *__restrict __stream,

const char *__restrict __format, …);

extern int printf (const char *__restrict __format, …);
extern int sprintf (char *restrict __s,
const char *__restrict __format, …) __attribute ((nothrow));
extern int vfprintf (FILE *__restrict __s, const char *__restrict __format,

__gnuc_va_list __arg);

extern int vprintf (const char *__restrict __format, __gnuc_va_list __arg);
extern int vsprintf (char *restrict __s, const char *__restrict __format,
__gnuc_va_list __arg) __attribute ((nothrow));
extern int snprintf (char *restrict __s, size_t __maxlen,
const char *__restrict __format, …)
__attribute ((nothrow)) attribute ((format (printf, 3, 4)));
extern int vsnprintf (char *restrict __s, size_t __maxlen,
const char *__restrict __format, __gnuc_va_list __arg)
__attribute ((nothrow)) attribute ((format (printf, 3, 0)));
379 "/usr/include/stdio.h" 3 4
extern int vdprintf (int fd, const char *__restrict __fmt,
__gnuc_va_list __arg)
__attribute ((format (printf, 2, 0)));

extern int dprintf (int fd, const char *__restrict __fmt, …)
__attribute ((format (printf, 2, 3)));
extern int fscanf (FILE *__restrict __stream,

const char *__restrict __format, …) ;

extern int scanf (const char *__restrict __format, …) ;
extern int sscanf (const char *restrict __s,
const char *__restrict __format, …) __attribute ((nothrow , leaf));
extern int fscanf (FILE *restrict __stream, const char *__restrict __format, …) __asm ("" "__isoc99_fscanf")
;
extern int scanf (const char *restrict __format, …) __asm ("" "isoc99_scanf")
;
extern int sscanf (const char *__restrict __s, const char *__restrict __format, …) __asm ("" "isoc99_sscanf") __attribute ((nothrow , leaf))
;
432 "/usr/include/stdio.h" 3 4
extern int vfscanf (FILE *restrict __s, const char *__restrict __format,
__gnuc_va_list __arg)
__attribute ((format (scanf, 2, 0))) ;
extern int vscanf (const char *restrict __format, __gnuc_va_list __arg)
__attribute ((format (scanf, 1, 0))) ;
extern int vsscanf (const char *restrict __s,
const char *__restrict __format, __gnuc_va_list __arg)
__attribute ((nothrow , leaf)) attribute ((format (scanf, 2, 0)));
extern int vfscanf (FILE *restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm ("" "__isoc99_vfscanf")
attribute ((format (scanf, 2, 0))) ;
extern int vscanf (const char *restrict __format, __gnuc_va_list __arg) __asm ("" "__isoc99_vscanf")
attribute ((format (scanf, 1, 0))) ;
extern int vsscanf (const char *restrict __s, const char *__restrict __format, __gnuc_va_list __arg) __asm ("" "isoc99_vsscanf") __attribute ((nothrow , leaf))
attribute ((format (scanf, 2, 0)));
485 "/usr/include/stdio.h" 3 4
extern int fgetc (FILE *__stream);

extern int getc (FILE *__stream);
extern int getchar (void);
extern int getc_unlocked (FILE *__stream);

extern int getchar_unlocked (void);
510 "/usr/include/stdio.h" 3 4
extern int fgetc_unlocked (FILE *__stream);
521 "/usr/include/stdio.h" 3 4
extern int fputc (int __c, FILE *__stream);

extern int putc (int __c, FILE *__stream);
extern int putchar (int __c);
537 "/usr/include/stdio.h" 3 4
extern int fputc_unlocked (int __c, FILE *__stream);
extern int putc_unlocked (int __c, FILE *__stream);

extern int putchar_unlocked (int __c);
extern int getw (FILE *__stream);
extern int putw (int __w, FILE *__stream);
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)

;

603 "/usr/include/stdio.h" 3 4
extern __ssize_t __getdelim (char **__restrict __lineptr,

size_t *__restrict __n, int __delimiter,

FILE *__restrict __stream) ;

extern __ssize_t getdelim (char **__restrict __lineptr,

size_t *__restrict __n, int __delimiter,

FILE *__restrict __stream) ;

extern __ssize_t getline (char **__restrict __lineptr,

size_t *__restrict __n,

FILE *__restrict __stream) ;

extern int fputs (const char *__restrict __s, FILE *__restrict __stream);
extern int puts (const char *__s);
extern int ungetc (int __c, FILE *__stream);
extern size_t fread (void *__restrict __ptr, size_t __size,

size_t __n, FILE *__restrict __stream) ;

extern size_t fwrite (const void *__restrict __ptr, size_t __size,

size_t __n, FILE *__restrict __s);

673 "/usr/include/stdio.h" 3 4
extern size_t fread_unlocked (void *__restrict __ptr, size_t __size,

size_t __n, FILE *__restrict __stream) ;

extern size_t fwrite_unlocked (const void *__restrict __ptr, size_t __size,

size_t __n, FILE *__restrict __stream);

extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream) ;
extern void rewind (FILE *__stream);
707 "/usr/include/stdio.h" 3 4
extern int fseeko (FILE *__stream, __off_t __off, int __whence);
extern __off_t ftello (FILE *__stream) ;
731 "/usr/include/stdio.h" 3 4
extern int fgetpos (FILE *__restrict __stream, fpos_t *__restrict __pos);
extern int fsetpos (FILE *__stream, const fpos_t *__pos);
757 "/usr/include/stdio.h" 3 4
extern void clearerr (FILE *stream) __attribute ((nothrow , leaf));
extern int feof (FILE *stream) __attribute ((nothrow , leaf)) ;
extern int ferror (FILE *stream) __attribute ((nothrow , leaf)) ;
extern void clearerr_unlocked (FILE *stream) __attribute ((nothrow , leaf));

extern int feof_unlocked (FILE *stream) __attribute ((nothrow , leaf)) ;

extern int ferror_unlocked (FILE *stream) __attribute ((nothrow , leaf)) ;
extern void perror (const char *__s);
1 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 1 3 4
26 "/usr/include/x86_64-linux-gnu/bits/sys_errlist.h" 3 4
extern int sys_nerr;

extern const char *const sys_errlist[];
782 "/usr/include/stdio.h" 2 3 4
extern int fileno (FILE *stream) __attribute ((nothrow , leaf)) ;
extern int fileno_unlocked (FILE *stream) __attribute ((nothrow , leaf)) ;
800 "/usr/include/stdio.h" 3 4
extern FILE *popen (const char *__command, const char *__modes) ;
extern int pclose (FILE *__stream);
extern char *ctermid (char *s) __attribute ((nothrow , leaf));
840 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *stream) __attribute ((nothrow , leaf));
extern int ftrylockfile (FILE *stream) __attribute ((nothrow , leaf)) ;
extern void funlockfile (FILE *stream) __attribute ((nothrow , leaf));
858 "/usr/include/stdio.h" 3 4
extern int __uflow (FILE *);

extern int __overflow (FILE *, int);
873 "/usr/include/stdio.h" 3 4
2 "helloworld.c" 2
2 "helloworld.c"
int main(){

printf("Hello World\n");

return 0;

}

Entry Point of the application

/*Start of the code.*/

int main() 

It is an entry point in the code where the application will start running.

/*Using prinf to print the given string within bracket().*/

printf("Hello World");

This statement will allow the executable to print the string within the double quote “.

Return status of the application

/*Retruning the status of the program or function.*/

return 0;

It returns to status 0 to the process which will call the executable.

Code block or Scope of the code

{} represent the block of the function.

Translation to low level code

Once, we compile this written program text file it gets converted into a low-level (Microcontroller) program.

gcc -S helloworld.c && cat helloworld.s
	.file	"helloworld.c"
	.text
	.section	.rodata
.LC0:
	.string	"Hello World"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	endbr64
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	leaq	.LC0(%rip), %rdi
	call	puts@PLT
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
	.section	.note.GNU-stack,"",@progbits
	.section	.note.gnu.property,"a"
	.align 8
	.long	 1f - 0f
	.long	 4f - 1f
	.long	 5
0:
	.string	 "GNU"
1:
	.align 8
	.long	 0xc0000002
	.long	 3f - 2f
2:
	.long	 0x3
3:
	.align 8
4:

Compiling C code to assembly object

The above code is once you compile the helloworld.c but don’t assemble it. Once you compile and assemble it creates an object file result in helloworld.o. To compile the code without linking, you can run

gcc -c helloworld.c

It will generate the object code of the code. A helloworld.o file will be generated.

Creation of executable from source

Now let’s create an executable that will eventually run as a program.

gcc helloworld.c -o helloworld

This will generate the final binary of the code. Which can be executed as a program.

Upon running this executable you should see "Hello World" on the screen.

Source to binary journey

Here, the GCC compiler generates the HelloWorld executable which prints “Hello World”.

Journey to executable

Read more