1. 程式人生 > >C語言再學習 -- GCC編譯過程

C語言再學習 -- GCC編譯過程

一、GCC簡介:

gcc的原名叫做GNU C語言 編譯器(GNU C Compile),只能編譯C語言程式,後來很快就做了擴充套件,支援了更多的程式語言,比如C+ Object-c ...,改名為GNC 編譯器 套件(GNU Compile Collection) 支援很多的硬體和作業系統。

二、編譯過程

C語言的編譯過程可分為四個階段:預處理->>編譯->>彙編->>連結

下面以hello.c為示例詳細介紹各個編譯過程:

//示例hello.c
#include <stdio.h>
int main (void)
{
	printf ("hello world!\n");
	return 0;
}

1、預處理

預編譯過程主要處理那些原始碼中以#開始的預編譯指令,主要處理規則如下:
1)將所有的#define刪除,並且展開所有的巨集定義;
2)處理所有條件編譯指令,如#if,#ifdef等;
3)處理#include預編譯指令,將被包含的檔案插入到該預編譯指令的位置。該過程遞迴進行,及被包含的檔案可能還包含其他檔案。
4)刪除所有的註釋//和 /**/;
5)新增行號和檔案標識,如#2 “hello.c” 2,以便於編譯時編譯器產生除錯用的行號資訊及用於編譯時產生編譯錯誤或警告時能夠顯示行號資訊;
6)保留所有的#pragma編譯器指令,因為編譯器須要使用它們;

gcc -E hello.c -o hello.i

得到一個.i為字尾的預處理之後的檔案,該檔案叫做預處理檔案,以下為預處理後的輸出檔案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

/***** 省略了部分內容,包括stdio.h中的一些宣告及定義  *****/

# 2 "hello.c" 2
int main (void)
{
 printf ("hello world!\n");
 return 0;
}

2、編譯

編譯過程就是把預處理完的檔案進行一系列詞法分析,語法分析,語義分析及優化後生成相應的彙編程式碼檔案。

gcc -S hello.i -o hello.s得到一個.s為字尾的彙編檔案,以下為編譯後的輸出檔案hello.s的內容:

	.file	"hello.c"
	.section	.rodata
.LC0:
	.string	"hello world!"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$16, %esp
	movl	$.LC0, (%esp)
	call	puts
	movl	$0, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
	.section	.note.GNU-stack,"",@progbits

3、彙編

彙編器是將彙編程式碼轉變成機器可以執行的命令,每一個彙編語句幾乎都對應一條機器指令。彙編相對於編譯過程比較簡單,根據彙編指令和機器指令的對照表一一翻譯即可。

gcc –c hello.s –o hello.o,得到一個.o為字尾的目標檔案,由於hello.o的內容為機器碼,不能以文字形式方便的呈現。可用命令hexdump hello.o 開啟。

4、連結

目的碼不能直接執行,要想將目的碼變成可執行程式,還需要進行連結操作。才會生成真正可以執行的可執行程式。連結操作最重要的步驟就是將函式庫中相應的程式碼組合到目標檔案中。

gcc hello.o -o hello實現連結的處理,預設生成可執行檔案 a.out,可以通過 -o來指定輸出檔名。

使用ld指令
ld -static crt1.o crti.o crtbeginT.o hello.o -start -group -lgcc -lgcc_eh -lc -end-group crtend.o crtn.o 

(目標檔案,未指定具體目錄)
連線的過程包括按序疊加、相似段合併、符號地址的確定、符號解析與重定位、指令修正、全域性構造與解析等等

[email protected]:~/project/c_test$ gcc -v
使用內建 specs。
COLLECT_GCC=gcc.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
目標:i686-linux-gnu
配置為:../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
執行緒模型:posix
gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 

[email protected]:/$ find /usr -name crt*
/usr/lib/i386-linux-gnu/crti.o
/usr/lib/i386-linux-gnu/crt1.o
/usr/lib/i386-linux-gnu/crtn.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtbeginT.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtfastmath.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtend.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtprec80.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtprec32.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtbeginS.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtbegin.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtendS.o
/usr/lib/gcc/i686-linux-gnu/4.6/crtprec64.o
[email protected]:~/project/c_test$ ld -static -verbose /usr/lib/i386-linux-gnu/crt1.o /usr/lib/i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.6/crtbeginT.o -L/usr/lib/gcc/i686-linux-gnu/4.6 -L/usr/lib/i386-linux-gnu hello.o -start -group -lgcc -lgcc_eh -lc -end-group /usr/lib/gcc/i686-linux-gnu/4.6/crtend.o /usr/lib/i386-linux-gnu/crtn.o 
GNU ld (GNU Binutils for Ubuntu) 2.22
  Supported emulations:
   elf_i386
   i386linux
   elf32_x86_64
   elf_x86_64
   elf_l1om
   elf_k1om
ld: bad -rpath option 
gcc版本不對,支援的是 i386linux,如果想深入研究,安裝gcc 4.1.2

可以直接通過 gcc hello.c -o hello來生成可執行檔案,這只是把中步操作隱藏起來了

注意:gcc -c hello.o -o hello 是錯誤的

[email protected]:~/project/c_test$ gcc -c hello.o -o hello
gcc.real: 警告: hello.o:未使用連結器輸入檔案,因為連結尚未完成

注意:目標檔案和可執行檔案的不同

# gcc -c hello.c 
生成 hello.o  /*目標檔案*/
# file hello.o
hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

# readelf -h hello.o 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          288 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         13
  Section header string table index: 10
# gcc hello.o -o hello
生成 hello  /*可執行檔案*/
# file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x25c438a7052180bb74c1b9d78b498e6777586c92, not stripped

# readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048320
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4412 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         30
================================================
# arm-linux-gcc -c hello.c  
生成 hello.o  /*二進位制目標檔案*/
# file hello.o
hello.o: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

# readelf -h hello.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          288 (bytes into file)
  Flags:                             0x5000000, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 9
# arm-linux-gcc hello.o -o hello  
生成 hello  /*二進位制可執行檔案*/
# file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped

# readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x8304
  Start of program headers:          52 (bytes into file)
  Start of section headers:          4464 (bytes into file)
  Flags:                             0x5000002, has entry point, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         10
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 26

readelf -h 選項,讀取ELF檔案的檔案頭資訊,注意其中的三項值:Type、Machine、Entry point address

Type  資訊就是file中的檔案型別
Machine  是在ARM執行還是在inter執行的
Entry point address  表示檔案的執行入口點,只有可執行檔案該項才有值,而目標檔案是可重定向檔案,還不可以直接執行,因此該項值為0.

如果在ARM上執行目標檔案而不是可執行檔案會出現如下錯誤:
line 1: syntax error: unexpected word (expecting ")")

總之一句話,你要明白你編譯出來的是什麼

三、檔名字尾

[email protected]:~/project/c_test$ ls
hello  hello.c  hello.i  hello.o  hello.s

檔名字尾 

檔案型別

.c

C原始檔

.C .cpp .cc .c++ .cxx               

C++原始檔

.h

標頭檔案

.i

預處理後的C原始檔                           

.s

彙編程式檔案

.o

目標檔案

.a

靜態連結庫

.so

動態連結庫

四、gcc 常用命令

GCC編譯器非常強大,在各個發行的 linux  系統中都非常流行,本文介紹的是一些常用的 gcc 編譯選型。

下面這段程式碼將回繞整個文章:

編譯 hello.c 如下:

#include <stdio.h>

int main (void)
{
	printf ("hello world!\n");
	return 0;
}
GCC 編譯選項:

1、指定輸出可執行檔案的名字

使用最基本的gcc編譯格式

gcc hello.c
生成 a.out 
執行完上面這句命令,會在當前目錄下輸出一個名為 a.out 的可執行檔案。

使用 -o 選項可以指定輸出的可執行檔名稱。

gcc hello.c -o hello
生成 hello

執行完上面這句命令,會在當前目錄下輸出一個名為 hello 的可執行檔案。

2、讓所有編譯警告都顯示出來,選項 -Wall

如下,編輯一段警告的程式碼

#include <stdio.h>

int main (void)
{
	int i;
	printf ("\n hello world![i]\n", i);
	return 0;
}

[email protected]:/home/tarena/project/c_test# gcc -Wall hello.c -o hello
hello.c: 在函式‘main’中:
hello.c:6:2: 警告: 提供給格式字串的實參太多 [-Wformat-extra-args]
hello.c:6:9: 警告: 此函式中的‘i’在使用前未初始化 [-Wuninitialized]

3、指定 -E 編譯選項,使得只輸出預編譯結果

gcc -E hello.c -o hello.i
生成 helo.i

4、通過編譯選項 -S 輸出彙編程式碼

gcc -S hello.c
生成 hello.s

5、指定 -c 輸出編譯後的程式碼

gcc -c hello.c
生成 hello.o

6、通過編譯選項 -save-temps 輸出所有的中間程式碼

[email protected]:/home/tarena/project/c_test# gcc -save-temps hello.c 
[email protected]:/home/tarena/project/c_test# ls
a.out  hello.c  hello.i  hello.o  hello.s

7、連結共享庫 (動態連結庫)指定編譯選項 -l

gcc hello.c -o hello -lCPPfile
gcc 命令在執行連結 hello.c 程式碼時,會連結上 -lCPPfile 動態連結庫來生成 hello 可執行檔案。

8、指定編譯選項 -fPIC 建立獨立的(無關聯的)地址資訊程式碼

當建立動態連結庫時,獨立位置資訊(position independent)程式碼也需要生成。這可以幫助動態連結庫或者跟多的載入地址資訊來替代其他相對的地址資訊。所以-fPIC這個選項作用很大,能快速準確定位錯誤地址。
下面是一個例子,

$ gcc -c -Wall -Werror -fPIC Cfile.c  
$ gcc -shared -o libCfile.so Cfile.o  

9、檢視gcc版本資訊選項 -v

[email protected]:/home/tarena/project/c_test# gcc -v
使用內建 specs。
COLLECT_GCC=gcc.real
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper
目標:i686-linux-gnu
配置為:../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
執行緒模型:posix
gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 

10、指定編譯選項 -ansi,支援 ISO C89 程式

通過-ansi 選項開啟支援 ISO C89 風格,看如下程式碼:

[email protected]:/home/tarena/project/c_test# gcc -ansi hello.c 
hello.c: 在函式‘main’中:
hello.c:5:2: 錯誤: expected expression before ‘/’ token

11、指定編譯選項 -funsigned-char 選項將 char 型別解釋為 unsigned char 型別

#include <stdio.h>

int main (void)
{
	char c = -10;
	printf ("c is %d\n", c);
	return 0;
}

[email protected]:/home/tarena/project/c_test# gcc hello.c 
[email protected]:/home/tarena/project/c_test# ./a.out 
c is -10
[email protected]:/home/tarena/project/c_test# gcc -funsigned-char hello.c 
[email protected]:/home/tarena/project/c_test# ./a.out 
c is 246
[email protected]:/home/tarena/project/c_test# 

12、指定 -D 選型開啟編譯時的巨集

#include <stdio.h>  
int main()  
{  
    int num=0;  
    int arr[SIZE]={};   //使用gcc -D可以巨集定義這個數字  
    for(num = 0;num <= SIZE - 1;num++)  
    {  
        arr[num]=num;  
        printf("%d ",arr[num]);  
    }  
    printf("\n");  
    return 0;  
}  
gcc -DSIZE=4 define.c  
輸出結果:  
0 1 2 3  

13、將編譯警告轉換成錯誤的選項 -Werror

編譯警告很多時候會被我們忽視,在特殊場合我們還是需要重視編譯警告的,如果能把編譯警告變成直接輸出錯誤,那我們的重視程度會提高很多並去解決。

#include <stdio.h>

int main (void)
{
	int i;
	printf ("\n hello world![i]\n", i);
	return 0;
}

[email protected]:/home/tarena/project/c_test# gcc -Wall -Werror hello.c
hello.c: 在函式‘main’中:
hello.c:6:2: 錯誤: 提供給格式字串的實參太多 [-Werror=format-extra-args]
cc1: all warnings being treated as errors
上述程式碼未初始化變數 c ,警告變成了錯誤提示。

14、通過檔案制定編譯選項,指定@編譯選項

比較神奇的功能,可以使用@編譯選項然後跟著檔名,例如:

[email protected]:/home/tarena/project/c_test# cat opt_file 
-o hello
[email protected]:/home/tarena/project/c_test# gcc hello.c @opt_file
生成 hello

15、指定採用什麼版本的規範進行編譯,選項 -std

加上 -std=c89/-std=c99

[email protected]:/home/tarena/project/c_test# gcc -std=c99 hello.c
生成 a.out

16、優化程式選項 -O

優化是編譯器的一部分,它可以檢查和組合編譯器生成的程式碼,指出未達到最優的部分,並重新生成它們,從而使使用者編寫的程式更加完美且節省空間。在gcc編譯器選項中,使用-O選項對程式碼進行優化。優化級別分3級,由高到低分別為:-O3、-O2、-O1
優化程式選項說明:
-O1(-O): 對編譯出的程式碼進行優化
-O2: 進行比-O高一級的優化
-O3: 產生更高級別的優化

說明:
-O1(或-O)、-O2、-O3分別代表優化級別,數字越高,代表gcc的優化級別越高,高的優化級別代表著程式將執行的更快。優化級別越高則程式量越大。直接優化程式本身,效能的提高的變化更加明顯。

缺點,編譯、連結的速度就相應地要慢一些。

17、連線程式選項

庫:是一組預先編譯好的函式集合。
說明:
標準庫檔案一般儲存在/lib和/usr/lib目錄中。所有的庫名都以lib開頭。例如:libc.so(標準C語言函式庫)、libm.so(數學運算函式庫)以.a結尾的是靜態庫;以.so結尾的庫是動態庫。使用ar工具將目標檔案收集起來,放到一個歸檔檔案中。
連線程式選項說明:
-L dir:將dir所指出的目錄加到“函式庫搜尋列表”中,dir 為庫檔案所在的路徑
-llib: 連結lib庫,lib 為庫名
-I name: 連線時,載入名字為name的函式庫。該庫位於系統預設的目錄或者由-L選項確定的目錄下。實際的庫名是libname(字尾為.a或.so)

連結過程通常的形式如下:

gcc file.o -o file -lxxx -L dirname 

-L:指定了連結時用到的庫檔案所在的目錄。
-lxxx:指示連結的庫函式名為libxxx.a

例子:編譯產生可執行檔案hello,搜尋數學庫以解決問題。

# gcc hello.o -o hello  /usr/lib/libm.a
或者
# gcc -o hello hello.c -lm 

比如,使用pow冪函式,當指數為變數時,編譯出現undefined reference to `pow‘的錯誤

因為math.h不是C執行庫函式,就像linux下執行緒函式庫pthread.h也不是,都需要在編譯時連線該庫。如果你有

IDE(如eclipse)+ GCC 開發C程式,可以在專案屬性中編譯命令中新增-lm,作用是一樣的。

#include <stdio.h>  
#include <math.h>  
  
int main (void)  
{  
    int n = 2, m = 2;  
    int i = pow (2, m);  
    printf ("i = %d\n", i);  
    return 0;  
}  
編譯:gcc test.c -lm  
輸出結果:  
i = 4  

18、指定標頭檔案的路徑dir,選項 -I dir
先在指定的路徑中搜索要包含的標頭檔案,若找不到,則在標準路徑(/usr/include,/usr/lib及當前工作目錄)上搜索

#include "add.h"
int main (void)
{
	printf ("hello world!\n");
	return 0;
}

[email protected]:/home/tarena/project/c_test# gcc hello.c 
hello.c:1:17: 致命錯誤: add.h:沒有那個檔案或目錄
編譯中斷。
[email protected]:/home/tarena/project/c_test# gcc hello.c -I ../    /*上一個目錄查詢*/
[email protected]:/home/tarena/project/c_test# ./a.out 
hello world!
[email protected]:/home/tarena/project/c_test# 

19、除錯選型 -g

可產生供gdb除錯用的可執行檔案,大小明顯比只用-o選項編譯彙編連線後的檔案大。

[email protected]:/home/tarena/project/c_test# gcc hello.c 
[email protected]:/home/tarena/project/c_test# ls -la a.out 
-rwxr-xr-x 1 root root 7159 Nov 26 23:32 a.out
[email protected]:/home/tarena/project/c_test# gcc -g hello.c 
[email protected]:/home/tarena/project/c_test# ls -la a.out 
-rwxr-xr-x 1 root root 8051 Nov 26 23:32 a.out

gdb的簡單使用:

(gdb)l  列表(list)
(gdb)r  執行(run)
(gdb)n  下一個(next)
(gdb)q  退出(quit)
(gdb)p  輸出(print)
(gdb)c  繼續(continue)
(gdb)b 4 設定斷點(break)
(gdb)d   刪除斷點(delete)

[email protected]:/home/tarena/project/c_test# gdb a.out
GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/tarena/project/c_test/a.out...done.
(gdb) l
1	#include <stdio.h>
2	int main (void)
3	{
4		printf ("hello world!\n");
5		return 0;
6	}
(gdb) r
Starting program: /home/tarena/project/c_test/a.out 
hello world!
[Inferior 1 (process 6906) exited normally]
(gdb) q
[email protected]:/home/tarena/project/c_test# 

擴充套件:可使用 man gcc/cc 查詢 gcc/cc的更多相關資訊和選項

五、後續應用

這裡面的問題,line 1: syntax error: unexpected word (expecting ")")   值得看一下。


相關推薦

C語言學習 -- GCC編譯過程

一、GCC簡介:gcc的原名叫做GNU C語言 編譯器(GNU C Compile),只能編譯C語言程式,後來很快就做了擴充套件,支援了更多的程式語言,比如C+ Object-c ...,改名為GNC

C語言學習 -- 關鍵字struct(轉)

結構體的一般定義形式為: 標籤(tag)欄位允許為成員列表提供一個名字,這樣它就可以在後續的宣告中使用。標籤允許多個宣告使用同一個成員列表,並且建立同一種類型的結構。 struct 標籤{ 型別名1 成員名1; 型別名2 成員名2; …… 型別名n 成員名n;    }結構體變數;

C語言學習-定義變數

當我們在c語言裡建立一個變數的時候 int x = 5; int y = 6; 00C517B8 mov dword ptr [x],5 00C517BF mov dword ptr [y],6 實際上在彙編層面,

C語言學習5-陣列與優化

什麼是陣列?為什麼要用陣列? 通俗來講,在記憶體中一塊連續儲存資料的叫陣列,陣列的每個子元素的寬度都一樣,並且只能為通用的資料型別做單位(char,short,int等等) 讓我們先定義一個數組,然後賦值: char arr1[2] = { 0 }; arr1

C語言學習7-結構體

為什麼使用結構體? struct My { char name[20] = "如風斬嶽"; int age; char addr[50] ; int money; double Coordinates; //..... }; 當我們有這樣一種需求,

C語言學習--關鍵字

C語言一共有32個關鍵字,如下表所示: 關鍵字 說明 auto 宣告自動變數 short 宣告短整型變數或函式 int

C語言學習 -- 負數

有符號數的表示方法是由硬體決定,而不是由C決定的。有三種表示方法: 1、二進位制原碼 0000 0001  表示 1 1000 0001  表示 -1 這個方法有個缺點是有兩個零: +0 和 -0。這會引起混淆,而且用兩個位

C語言學習 -- 檔案

檔案是什麼 一個檔案(file)通常就是磁碟上的一段命名的儲存區。C 將檔案看成是連續的位元組序列,其中每一個位元組都可以單獨地讀取。 二進位制和文字模式 1、在windows系統中,文字模式

C語言學習 -- ASCII碼錶(轉)

ASCII碼錶第一部分:ASCII非列印控制字元表ASCII表上的數字0–31分配給了控制字元,用於控制像印表機等一些外圍裝置。例如,12代表換頁/新頁功能。此命令指示印表機跳到下一頁的開頭。(參詳ASCII碼錶中0-31)第二部分:ASCII列印字元數字 32–126 分配給了能在鍵盤上找到的字元,當您檢視

【 分類 】- C語言學習

專欄達人 授予成功建立個人部落格專欄

C語言學習 -- 詳解C++/C 面試題 1

對這篇文章記憶猶新,因為之前找工作面試的時候,遇到過一家公司就是用的這套面試題。現在就結合考查的知識點和我總結完 C 語言再學習後的深入理解,來詳細的講講我對這篇文章的總結。 一、請填寫BOOL ,

C語言學習 -- 論記憶體管理

但現在看來,缺少示例。從新再寫一篇文章,著重介紹常見記憶體錯誤、跨函式使用儲存區。開始吧,再論記憶體管理!!發生記憶體錯誤是件非常麻煩的事情。編譯器不能自動發現這些錯誤,通常是在程式執行時才能捕捉到。而這些錯誤大多沒有明顯的症狀時隱時現增加了改錯的難度。一、常見的記憶體錯誤及

C語言學習 -- 記憶體管理

malloc ( )函式: malloc ( ) 向系統申請分配指定size個位元組的記憶體空間。返回型別是 void* 型別。void* 表示未確定型別的指標。C,C++規定,void* 型別可

C語言學習 -- 關鍵字typedef

一、typedef 介紹 typedef為C語言的關鍵字,作用是為一種資料型別定義一個新名字。比如人們常常使用 typedef 來編寫更美觀和可讀的程式碼。所謂美觀,意指 tepe

C語言學習 -- 時間函式

gmtime函式:可以把time函式得到的結果按照格林尼治時間轉換成一個結構體localtime函式:可以把time函式得到的結果按照當前時區轉換成一個結構體asctime函式:可以把一個記錄時間的結構體轉換成字串,一般與上兩個函式合用的格林時間,與北京時間換算,/* 時間函式演示 */ #

C語言學習 -- 論陣列和指標

之前有總結指標陣列,但是現在看來總結的太簡單了。好多重要的知識點都是一帶而過的。本想在後面新增後來想想算了,還是再寫一篇文章來詳細介紹陣列和指標這對冤家吧。一開始覺得C語言再學習專欄都寫了五十篇了,現在

C語言學習 -- NUL和NULL的區別

NUL 是ASCII 字符集中 '\0' 字元的名字,它的位元組模式為全 0。NULL 指一個其值為 0 的指標。它們都是整型值,其值也相同,所以它們可以互換使用。然而,你還是應該使用適當的常量,因為

C語言學習 -- 段錯誤(核心已轉儲)

一、什麼是段錯誤?一旦一個程式發生了越界訪問,cpu 就會產生相應的保護,於是 segmentation fault 就出現了,通過上面的解釋,段錯誤應該就是訪問了不可訪問的記憶體,這個記憶體區要麼是不存在的,要麼是受到系統保護的,還有可能是缺少檔案或者檔案損壞。二、段錯誤產

C語言學習 -- 詳解C++/C 面試題 2

(經典)C語言測試:想成為嵌入式程式設計師應知道的0x10個基本問題。1、用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題) #define SENCONDS_PER_YE

C語言學習 -- 儲存型別關鍵字

C語言中有 5 個作為儲存類說明符的關鍵字,分別是 auto、register、static、extern 以及 typedef。關鍵字typedef 與記憶體儲存無關,由於語法原因被歸入此類。現在簡單瞭解一下這五個儲存類說明符的關鍵字:說明符 auto  表明一個變數具有自