IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

从C语言的Hello World说起

标点符 2013-07-07 18:00:06 累计浏览 7,645 次
本机暂存

   C语言基本上大学都教过,但是很多人应该和我一样学习的时候还使用的是Windows平台,对于其中要用到的编译等知识都不了解。今天就针对这种情况来重新学习一遍C语言。

#include <stdio.h>
main()
{
    printf("hello world\n");
}

   以上代码应该是最简单的C语言程序了,将上面的内容报错为hello.c,并通过gcc去编译它,具体使用到的指令为:

   $ gcc -g -Wall hello.c -o hello

   该命令将文件‘hello.c’中的代码编译为机器码并存储在可执行文件 ‘hello’中。机器码的文件名是通过 -o 选项指定的。该选项通常作为命令行中的最后一个参数。如果被省略,输出文件默认为 ‘a.out’。如果当前目录中与可执行文件重名的文件已经存在,它将被覆盖。

   选项 -Wall 开启编译器几乎所有常用的警告。编译器有很多其他的警告选项,但 -Wall 是最常用的。默认情况下GCC 不会产生任何警告信息。当编写 C 或 C++ 程序时编译器警告非常有助于检测程序存在的问题。 注意如果有用到math.h库等非gcc默认调用的标准库,请使用-lm参数。

   选项 “”-g”" 表示在生成的目标文件中带调试信息,调试信息可以在程序异常中止产生core后,帮助分析错误产生的源头,包括产生错误的文件名和行号等非常多有用的信息。

   执行万上述指令后我们发现有报错,具体内容为:

   hello.c:2:1: 警告: 返回类型默认为‘int’ [-Wreturn-type]

   hello.c: 在函数‘main’中:

   hello.c:5:1: 警告: 在有返回值的函数中,控制流程到达函数尾 [-Wreturn-type]

   解决上诉问题的方法非常的简单,只要将代码修改为:

#include <stdio.h>
int main()
{
    printf("hello world\n");
    return 0;
}

   不管采用上诉的哪种代码,在命令行直接执行编译出来的hello文件,即可看到输出的hello world。下面就来细讲整个编译的过程。

   compilation

   上图是一个hello的c程序由gcc编译器从源码文件hello.c中读取内容并将其翻译成为一个可执行的对象文件hello的过程。这个过程包含了几个阶段:

   1、预处理过程:预处理(cpp)根据以字符#开头的命令,修改原始的C程序。比如hello.c中的第一行的#include <stdio.h> 命令告诉预处理器读取系统头文件stdio.h的内容,插入到程序文本中。结果就得到里另一个C程序,通常是以*.i作为文件扩展名。

   可通过执行如下指令获得:gcc -E hello.c -o hello.i

   用记事本打开,可查看到如下的内容:

   # 1 “hello.c”

   # 1 “<built-in>”

   # 1 “<命令行>”

   # 1 “hello.c”

   # 1 “/usr/include/stdio.h” 1 3 4

   # 28 “/usr/include/stdio.h” 3 4

   # 1 “/usr/include/features.h” 1 3 4

   # 324 “/usr/include/features.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/predefs.h” 1 3 4

   # 325 “/usr/include/features.h” 2 3 4

   # 357 “/usr/include/features.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 1 3 4

   # 378 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.h” 1 3 4

   # 379 “/usr/include/x86_64-linux-gnu/sys/cdefs.h” 2 3 4

   # 358 “/usr/include/features.h” 2 3 4

   # 389 “/usr/include/features.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 1 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.h” 1 3 4

   # 5 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 2 3 4

   # 1 “/usr/include/x86_64-linux-gnu/gnu/stubs-64.h” 1 3 4

   # 10 “/usr/include/x86_64-linux-gnu/gnu/stubs.h” 2 3 4

   # 390 “/usr/include/features.h” 2 3 4

   # 29 “/usr/include/stdio.h” 2 3 4

   # 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 1 3 4

   # 212 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 3 4

   typedef long unsigned int size_t;

   # 35 “/usr/include/stdio.h” 2 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/types.h” 1 3 4

   # 28 “/usr/include/x86_64-linux-gnu/bits/types.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/wordsize.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 long int __quad_t;

   typedef unsigned long int __u_quad_t;

   # 131 “/usr/include/x86_64-linux-gnu/bits/types.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/typesizes.h” 1 3 4

   # 132 “/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 long int __swblk_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 __ssize_t;

   typedef __off64_t __loff_t;

   typedef __quad_t *__qaddr_t;

   typedef char *__caddr_t;

   typedef long int __intptr_t;

   typedef unsigned int __socklen_t;

   # 37 “/usr/include/stdio.h” 2 3 4

   # 45 “/usr/include/stdio.h” 3 4

   struct _IO_FILE;

   typedef struct _IO_FILE FILE;

   # 65 “/usr/include/stdio.h” 3 4

   typedef struct _IO_FILE __FILE;

   # 75 “/usr/include/stdio.h” 3 4

   # 1 “/usr/include/libio.h” 1 3 4

   # 32 “/usr/include/libio.h” 3 4

   # 1 “/usr/include/_G_config.h” 1 3 4

   # 15 “/usr/include/_G_config.h” 3 4

   # 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h” 1 3 4

   # 16 “/usr/include/_G_config.h” 2 3 4

   # 1 “/usr/include/wchar.h” 1 3 4

   # 83 “/usr/include/wchar.h” 3 4

   typedef struct

   {

   int __count;

   union

   {

   unsigned int __wch;

   char __wchb[4];

   } __value;

   } __mbstate_t;

   # 21 “/usr/include/_G_config.h” 2 3 4

   typedef struct

   {

   __off_t __pos;

   __mbstate_t __state;

   } _G_fpos_t;

   typedef struct

   {

   __off64_t __pos;

   __mbstate_t __state;

   } _G_fpos64_t;

   # 53 “/usr/include/_G_config.h” 3 4

   typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));

   typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));

   typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));

   typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));

   # 33 “/usr/include/libio.h” 2 3 4

   # 53 “/usr/include/libio.h” 3 4

   # 1 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h” 1 3 4

   # 40 “/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h” 3 4

   typedef __builtin_va_list __gnuc_va_list;

   # 54 “/usr/include/libio.h” 2 3 4

   # 172 “/usr/include/libio.h” 3 4

   struct _IO_jump_t; struct _IO_FILE;

   # 182 “/usr/include/libio.h” 3 4

   typedef void _IO_lock_t;

   struct _IO_marker {

   struct _IO_marker *_next;

   struct _IO_FILE *_sbuf;

   int _pos;

   # 205 “/usr/include/libio.h” 3 4

   };

   enum __codecvt_result

   {

   __codecvt_ok,

   __codecvt_partial,

   __codecvt_error,

   __codecvt_noconv

   };

   # 273 “/usr/include/libio.h” 3 4

   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;

   # 321 “/usr/include/libio.h” 3 4

   __off64_t _offset;

   # 330 “/usr/include/libio.h” 3 4

   void *__pad1;

   void *__pad2;

   void *__pad3;

   void *__pad4;

   size_t __pad5;

   int _mode;

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

   };

   typedef struct _IO_FILE _IO_FILE;

   struct _IO_FILE_plus;

   extern struct _IO_FILE_plus _IO_2_1_stdin_;

   extern struct _IO_FILE_plus _IO_2_1_stdout_;

   extern struct _IO_FILE_plus _IO_2_1_stderr_;

   # 366 “/usr/include/libio.h” 3 4

   typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);

   typedef __ssize_t __io_write_fn (void *__cookie, __const char *__buf,

   size_t __n);

   typedef int __io_seek_fn (void *__cookie, __off64_t *__pos, int __w);

   typedef int __io_close_fn (void *__cookie);

   # 418 “/usr/include/libio.h” 3 4

   extern int __underflow (_IO_FILE *);

   extern int __uflow (_IO_FILE *);

   extern int __overflow (_IO_FILE *, int);

   # 462 “/usr/include/libio.h” 3 4

   extern int _IO_getc (_IO_FILE *__fp);

   extern int _IO_putc (int __c, _IO_FILE *__fp);

   extern int _IO_feof (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));

   extern int _IO_ferror (_IO_FILE *__fp) __attribute__ ((__nothrow__ , __leaf__));

   extern int _IO_peekc_locked (_IO_FILE *__fp);

   extern void _IO_flockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));

   extern void _IO_funlockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));

   extern int _IO_ftrylockfile (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));

   # 492 “/usr/include/libio.h” 3 4

   extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,

   __gnuc_va_list, int *__restrict);

   extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,

   __gnuc_va_list);

   extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);

   extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);

   extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);

   extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);

   extern void _IO_free_backup_area (_IO_FILE *) __attribute__ ((__nothrow__ , __leaf__));

   # 76 “/usr/include/stdio.h” 2 3 4

   typedef __gnuc_va_list va_list;

   # 91 “/usr/include/stdio.h” 3 4

   typedef __off_t off_t;

   # 103 “/usr/include/stdio.h” 3 4

   typedef __ssize_t ssize_t;

   typedef _G_fpos_t fpos_t;

   # 165 “/usr/include/stdio.h” 3 4

   # 1 “/usr/include/x86_64-linux-gnu/bits/stdio_lim.h” 1 3 4

   # 166 “/usr/include/stdio.h” 2 3 4

   extern struct _IO_FILE *stdin;

   extern struct _IO_FILE *stdout;

   extern struct _IO_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__));

   extern FILE *tmpfile (void) ;

   # 210 “/usr/include/stdio.h” 3 4

   extern char *tmpnam (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;

   extern char *tmpnam_r (char *__s) __attribute__ ((__nothrow__ , __leaf__)) ;

   # 228 “/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);

   # 253 “/usr/include/stdio.h” 3 4

   extern int fflush_unlocked (FILE *__stream);

   # 267 “/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) ;

   # 296 “/usr/include/stdio.h” 3 4

   # 307 “/usr/include/stdio.h” 3 4

   extern FILE *fdopen (int __fd, __const char *__modes) __attribute__ ((__nothrow__ , __leaf__)) ;

   # 320 “/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)));

   # 418 “/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__));

   # 449 “/usr/include/stdio.h” 3 4

   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__))

   ;

   # 469 “/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)));

   # 500 “/usr/include/stdio.h” 3 4

   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)));

   # 528 “/usr/include/stdio.h” 3 4

   extern int fgetc (FILE *__stream);

   extern int getc (FILE *__stream);

   extern int getchar (void);

   # 556 “/usr/include/stdio.h” 3 4

   extern int getc_unlocked (FILE *__stream);

   extern int getchar_unlocked (void);

   # 567 “/usr/include/stdio.h” 3 4

   extern int fgetc_unlocked (FILE *__stream);

   extern int fputc (int __c, FILE *__stream);

   extern int putc (int __c, FILE *__stream);

   extern int putchar (int __c);

   # 600 “/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)

   ;

   extern char *gets (char *__s) ;

   # 662 “/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);

   # 734 “/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);

   # 770 “/usr/include/stdio.h” 3 4

   extern int fseeko (FILE *__stream, __off_t __off, int __whence);

   extern __off_t ftello (FILE *__stream) ;

   # 789 “/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);

   # 812 “/usr/include/stdio.h” 3 4

   # 821 “/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

   # 27 “/usr/include/x86_64-linux-gnu/bits/sys_errlist.h” 3 4

   extern int sys_nerr;

   extern __const char *__const sys_errlist[];

   # 851 “/usr/include/stdio.h” 2 3 4

   extern int fileno (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;

   extern int fileno_unlocked (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;

   # 870 “/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__));

   # 910 “/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__));

   # 940 “/usr/include/stdio.h” 3 4

   # 2 “hello.c” 2

   int main()

   {

   printf(“hello world\n”);

   return 0;

   }

   以上部分代码可以看出除了#include <stdio.h>指令之外其他指令并未被改变。

   2、编译阶段:编译器将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文件格式确切地描述了一条低级机器语言指令。

   可通过如下指令获得:gcc -S hello.c -o hello.s

   用记事本打开,可查看到如下的内容:

   .file “hello.c”

   .section .rodata

   .LC0:

   .string “hello world”

   .text

   .globl main

   .type main, @function

   main:

   .LFB0:

   .cfi_startproc

   pushq %rbp

   .cfi_def_cfa_offset 16

   .cfi_offset 6, -16

   movq %rsp, %rbp

   .cfi_def_cfa_register 6

   movl $.LC0, %edi

   call puts

   movl $0, %eax

   popq %rbp

   .cfi_def_cfa 7, 8

   ret

   .cfi_endproc

   .LFE0:

   .size main, .-main

   .ident “GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3″

   .section .note.GNU-stack,”",@progbits

   3、汇编阶段:汇编器将hello.s翻译成机器语言指令,把这些指令打包成一种可重定位目标程序的格式,并把结果保存在hello.o中,hello.o是一个二进制文件,它的字节编码是机器语言指令,而不是字符。

   可通过如下指令获得:gcc -c hello.c,最终生成的hello.o文件需要使用objdump打开,具体指令为:objdump -d hello.o

   获取的内容为:

   hello.o: file format elf64-x86-64

   Disassembly of section .text:

   0000000000000000 <main>:

   0: 55 push %rbp

   1: 48 89 e5 mov %rsp,%rbp

   4: bf 00 00 00 00 mov $0×0,%edi

   9: e8 00 00 00 00 callq e <main+0xe>

   e: b8 00 00 00 00 mov $0×0,%eax

   13: 5d pop %rbp

   14: c3 retq

   4.、链接阶段:hello.c程序中调用了printf函数,而printf函数存在于一个名为printf.o的单独的预编译好的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器就负责处理这种合并,结果就得到hello文件,它是一个可执行文件,可以被加载到内存中由系统执行。

   使用的指令为:gcc hello.o -o hello,最终生成了一个hello文件,同样此hello文件可用通过objdump打开:objdump -d hello

   打开后的内容为:

   hello: file format elf64-x86-64

   Disassembly of section .init:

   00000000004003c8 <_init>:

   4003c8: 48 83 ec 08 sub $0×8,%rsp

   4003cc: e8 6b 00 00 00 callq 40043c <call_gmon_start>

   4003d1: e8 fa 00 00 00 callq 4004d0 <frame_dummy>

   4003d6: e8 d5 01 00 00 callq 4005b0 <__do_global_ctors_aux>

   4003db: 48 83 c4 08 add $0×8,%rsp

   4003df: c3 retq

   Disassembly of section .plt:

   00000000004003e0 <puts@plt-0×10>:

   4003e0: ff 35 0a 0c 20 00 pushq 0x200c0a(%rip) # 600ff0 <_GLOBAL_OFFSET_TABLE_+0×8>

   4003e6: ff 25 0c 0c 20 00 jmpq *0x200c0c(%rip) # 600ff8 <_GLOBAL_OFFSET_TABLE_+0×10>

   4003ec: 0f 1f 40 00 nopl 0×0(%rax)

   00000000004003f0 <puts@plt>:

   4003f0: ff 25 0a 0c 20 00 jmpq *0x200c0a(%rip) # 601000 <_GLOBAL_OFFSET_TABLE_+0×18>

   4003f6: 68 00 00 00 00 pushq $0×0

   4003fb: e9 e0 ff ff ff jmpq 4003e0 <_init+0×18>

   0000000000400400 <__libc_start_main@plt>:

   400400: ff 25 02 0c 20 00 jmpq *0x200c02(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0×20>

   400406: 68 01 00 00 00 pushq $0×1

   40040b: e9 d0 ff ff ff jmpq 4003e0 <_init+0×18>

   Disassembly of section .text:

   0000000000400410 <_start>:

   400410: 31 ed xor %ebp,%ebp

   400412: 49 89 d1 mov %rdx,%r9

   400415: 5e pop %rsi

   400416: 48 89 e2 mov %rsp,%rdx

   400419: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp

   40041d: 50 push %rax

   40041e: 54 push %rsp

   40041f: 49 c7 c0 a0 05 40 00 mov $0x4005a0,%r8

   400426: 48 c7 c1 10 05 40 00 mov $0×400510,%rcx

   40042d: 48 c7 c7 f4 04 40 00 mov $0x4004f4,%rdi

   400434: e8 c7 ff ff ff callq 400400 <__libc_start_main@plt>

   400439: f4 hlt

   40043a: 90 nop

   40043b: 90 nop

   000000000040043c <call_gmon_start>:

   40043c: 48 83 ec 08 sub $0×8,%rsp

   400440: 48 8b 05 99 0b 20 00 mov 0x200b99(%rip),%rax # 600fe0 <_DYNAMIC+0×190>

   400447: 48 85 c0 test %rax,%rax

   40044a: 74 02 je 40044e <call_gmon_start+0×12>

   40044c: ff d0 callq *%rax

   40044e: 48 83 c4 08 add $0×8,%rsp

   400452: c3 retq

   400453: 90 nop

   400454: 90 nop

   400455: 90 nop

   400456: 90 nop

   400457: 90 nop

   400458: 90 nop

   400459: 90 nop

   40045a: 90 nop

   40045b: 90 nop

   40045c: 90 nop

   40045d: 90 nop

   40045e: 90 nop

   40045f: 90 nop

   0000000000400460 <__do_global_dtors_aux>:

   400460: 55 push %rbp

   400461: 48 89 e5 mov %rsp,%rbp

   400464: 53 push %rbx

   400465: 48 83 ec 08 sub $0×8,%rsp

   400469: 80 3d b0 0b 20 00 00 cmpb $0×0,0x200bb0(%rip) # 601020 <__bss_start>

   400470: 75 4b jne 4004bd <__do_global_dtors_aux+0x5d>

   400472: bb 40 0e 60 00 mov $0x600e40,%ebx

   400477: 48 8b 05 aa 0b 20 00 mov 0x200baa(%rip),%rax # 601028 <dtor_idx.6533>

   40047e: 48 81 eb 38 0e 60 00 sub $0x600e38,%rbx

   400485: 48 c1 fb 03 sar $0×3,%rbx

   400489: 48 83 eb 01 sub $0×1,%rbx

   40048d: 48 39 d8 cmp %rbx,%rax

   400490: 73 24 jae 4004b6 <__do_global_dtors_aux+0×56>

   400492: 66 0f 1f 44 00 00 nopw 0×0(%rax,%rax,1)

   400498: 48 83 c0 01 add $0×1,%rax

   40049c: 48 89 05 85 0b 20 00 mov %rax,0x200b85(%rip) # 601028 <dtor_idx.6533>

   4004a3: ff 14 c5 38 0e 60 00 callq *0x600e38(,%rax,8)

   4004aa: 48 8b 05 77 0b 20 00 mov 0x200b77(%rip),%rax # 601028 <dtor_idx.6533>

   4004b1: 48 39 d8 cmp %rbx,%rax

   4004b4: 72 e2 jb 400498 <__do_global_dtors_aux+0×38>

   4004b6: c6 05 63 0b 20 00 01 movb $0×1,0x200b63(%rip) # 601020 <__bss_start>

   4004bd: 48 83 c4 08 add $0×8,%rsp

   4004c1: 5b pop %rbx

   4004c2: 5d pop %rbp

   4004c3: c3 retq

   4004c4: 66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0×0(%rax,%rax,1)

   4004cb: 00 00 00 00 00

   00000000004004d0 <frame_dummy>:

   4004d0: 48 83 3d 70 09 20 00 cmpq $0×0,0×200970(%rip) # 600e48 <__JCR_END__>

   4004d7: 00

   4004d8: 55 push %rbp

   4004d9: 48 89 e5 mov %rsp,%rbp

   4004dc: 74 12 je 4004f0 <frame_dummy+0×20>

   4004de: b8 00 00 00 00 mov $0×0,%eax

   4004e3: 48 85 c0 test %rax,%rax

   4004e6: 74 08 je 4004f0 <frame_dummy+0×20>

   4004e8: 5d pop %rbp

   4004e9: bf 48 0e 60 00 mov $0x600e48,%edi

   4004ee: ff e0 jmpq *%rax

   4004f0: 5d pop %rbp

   4004f1: c3 retq

   4004f2: 90 nop

   4004f3: 90 nop

   00000000004004f4 <main>:

   4004f4: 55 push %rbp

   4004f5: 48 89 e5 mov %rsp,%rbp

   4004f8: bf fc 05 40 00 mov $0x4005fc,%edi

   4004fd: e8 ee fe ff ff callq 4003f0 <puts@plt>

   400502: b8 00 00 00 00 mov $0×0,%eax

   400507: 5d pop %rbp

   400508: c3 retq

   400509: 90 nop

   40050a: 90 nop

   40050b: 90 nop

   40050c: 90 nop

   40050d: 90 nop

   40050e: 90 nop

   40050f: 90 nop

   0000000000400510 <__libc_csu_init>:

   400510: 48 89 6c 24 d8 mov %rbp,-0×28(%rsp)

   400515: 4c 89 64 24 e0 mov %r12,-0×20(%rsp)

   40051a: 48 8d 2d 03 09 20 00 lea 0×200903(%rip),%rbp # 600e24 <__init_array_end>

   400521: 4c 8d 25 fc 08 20 00 lea 0x2008fc(%rip),%r12 # 600e24 <__init_array_end>

   400528: 4c 89 6c 24 e8 mov %r13,-0×18(%rsp)

   40052d: 4c 89 74 24 f0 mov %r14,-0×10(%rsp)

   400532: 4c 89 7c 24 f8 mov %r15,-0×8(%rsp)

   400537: 48 89 5c 24 d0 mov %rbx,-0×30(%rsp)

   40053c: 48 83 ec 38 sub $0×38,%rsp

   400540: 4c 29 e5 sub %r12,%rbp

   400543: 41 89 fd mov %edi,%r13d

   400546: 49 89 f6 mov %rsi,%r14

   400549: 48 c1 fd 03 sar $0×3,%rbp

   40054d: 49 89 d7 mov %rdx,%r15

   400550: e8 73 fe ff ff callq 4003c8 <_init>

   400555: 48 85 ed test %rbp,%rbp

   400558: 74 1c je 400576 <__libc_csu_init+0×66>

   40055a: 31 db xor %ebx,%ebx

   40055c: 0f 1f 40 00 nopl 0×0(%rax)

   400560: 4c 89 fa mov %r15,%rdx

   400563: 4c 89 f6 mov %r14,%rsi

   400566: 44 89 ef mov %r13d,%edi

   400569: 41 ff 14 dc callq *(%r12,%rbx,8)

   40056d: 48 83 c3 01 add $0×1,%rbx

   400571: 48 39 eb cmp %rbp,%rbx

   400574: 75 ea jne 400560 <__libc_csu_init+0×50>

   400576: 48 8b 5c 24 08 mov 0×8(%rsp),%rbx

   40057b: 48 8b 6c 24 10 mov 0×10(%rsp),%rbp

   400580: 4c 8b 64 24 18 mov 0×18(%rsp),%r12

   400585: 4c 8b 6c 24 20 mov 0×20(%rsp),%r13

   40058a: 4c 8b 74 24 28 mov 0×28(%rsp),%r14

   40058f: 4c 8b 7c 24 30 mov 0×30(%rsp),%r15

   400594: 48 83 c4 38 add $0×38,%rsp

   400598: c3 retq

   400599: 0f 1f 80 00 00 00 00 nopl 0×0(%rax)

   00000000004005a0 <__libc_csu_fini>:

   4005a0: f3 c3 repz retq

   4005a2: 90 nop

   4005a3: 90 nop

   4005a4: 90 nop

   4005a5: 90 nop

   4005a6: 90 nop

   4005a7: 90 nop

   4005a8: 90 nop

   4005a9: 90 nop

   4005aa: 90 nop

   4005ab: 90 nop

   4005ac: 90 nop

   4005ad: 90 nop

   4005ae: 90 nop

   4005af: 90 nop

   00000000004005b0 <__do_global_ctors_aux>:

   4005b0: 55 push %rbp

   4005b1: 48 89 e5 mov %rsp,%rbp

   4005b4: 53 push %rbx

   4005b5: 48 83 ec 08 sub $0×8,%rsp

   4005b9: 48 8b 05 68 08 20 00 mov 0×200868(%rip),%rax # 600e28 <__CTOR_LIST__>

   4005c0: 48 83 f8 ff cmp $0xffffffffffffffff,%rax

   4005c4: 74 19 je 4005df <__do_global_ctors_aux+0x2f>

   4005c6: bb 28 0e 60 00 mov $0x600e28,%ebx

   4005cb: 0f 1f 44 00 00 nopl 0×0(%rax,%rax,1)

   4005d0: 48 83 eb 08 sub $0×8,%rbx

   4005d4: ff d0 callq *%rax

   4005d6: 48 8b 03 mov (%rbx),%rax

   4005d9: 48 83 f8 ff cmp $0xffffffffffffffff,%rax

   4005dd: 75 f1 jne 4005d0 <__do_global_ctors_aux+0×20>

   4005df: 48 83 c4 08 add $0×8,%rsp

   4005e3: 5b pop %rbx

   4005e4: 5d pop %rbp

   4005e5: c3 retq

   4005e6: 90 nop

   4005e7: 90 nop

   Disassembly of section .fini:

   00000000004005e8 <_fini>:

   4005e8: 48 83 ec 08 sub $0×8,%rsp

   4005ec: e8 6f fe ff ff callq 400460 <__do_global_dtors_aux>

   4005f1: 48 83 c4 08 add $0×8,%rsp

   4005f5: c3 retq

   经过上面四个过程,我们就可以把一个源代码文件编译成机器能运行的可执行文件。这个可执行文件刚开始是保存在磁盘上,当计算机要运行这个程序的时候,hello就被加载到内存中,接着程序指令被不断复制到寄存器中由CPU来执行,最后把”hello world”从寄存器中打到显示设备上。这就是hello程序整个执行过程。

   大致的过程就这么多,关于中间涉及到的其他内容由于篇幅的限制,下篇文章再详述~尽请期待~

同分类推荐文章

  1. 科技爱好者周刊(第 401 期):如何赚到10亿美元 (2026-06-26 08:05:38)
  2. 如何做决策 - 从 Go 的一个 issue 说起 (2026-06-26 08:00:00)
  3. Seven Player:Windows上播放115网盘视频的增强工具 (2026-06-09 00:06:47)

查看更多 开发者 文章 →

建议继续学习

  1. 哪本书是对程序员最有影响、每个程序员都该阅读的书? (累计阅读 15,115)
  2. 看源代码那些事 (累计阅读 10,600)
  3. 谷歌(Google)2011年校园招聘笔试题 (累计阅读 9,574)
  4. 编程能力与编程年龄 (累计阅读 9,421)
  5. 你做过的最有效的提高你的编程水平的一件事情是什么 (累计阅读 9,062)
  6. 给想当程序员的大二学生的建议 (累计阅读 8,931)
  7. 再谈“我是怎么招聘程序员的” (累计阅读 8,792)
  8. 关于PHP的编译和执行分离 (累计阅读 8,345)
  9. 我学编程时犯的最大两个错误 (累计阅读 7,961)
  10. 一次简单C程序的性能优化 (累计阅读 6,852)