程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C99標准的新特性

C99標准的新特性

編輯:C++入門知識

C語言標准的發展

C語言的發展歷史大致上分為4個階段:Old Style C、C89、C99和C11.

C89是最早的C語言規范,於1989年提出,1990年先由ANSI(美國國家標准委員會,American National Standards Institute)推出ANSI版本,後來被接納為ISO國際標准(ISO/IEC9899:1990),因而有時也稱為C90,最經典的C語言教材[K&R]就是基於這個版本的,C89是目前最廣泛采用的C語言標准,大多數編譯器都完全支持C89,C99(ISO/IEC9899:1999)是在1999年推出的,加入了許多新的特性,但目前仍沒有得到廣泛支持,在C99推出之後相當長的一段時間裡,連gcc也沒有完全實現C99的所有特性。2011年12月8號,ISO 發布了新的 C 語言的新標准——C11,之前被稱為C1X,官方名稱 ISO/IEC 9899:2011。

本文地址:http://www.cnblogs.com/archimedes/p/c99-new-feature.html,轉載請注明源地址。

現在介紹一下C99相對於C89或者ANSI C的新特性:

1.復數(complex)

complex.h是C標准函數庫中的頭文件,提供了復數算術所需要的宏定義與函數聲明。

#define complex  _Complex
#define _Complex_I  ((const float _Complex)__I__)
#define I  _Complex_I

C99規定了關鍵字_Complex。因而有3種復數類型:

  • double _Complex
  • float _Complex
  • long double _Complex

次序不是必須遵守的,比如float _Complex也可以寫成_Complex float。_Complex_I擴展為類型為const float _Complex的常量值,其值為虛數單位。C99規定complex作為宏擴展為_Complex。但C++未定義complex宏。gcc僅支持complex type,不支持imaginary type。因此宏I擴展為_Complex_I

<complex.h>裡面還包含了不少支持復數的數學函數(c打頭的就是):

1、ccos,csin,ctan,cacos,casin,catan:復數域內的三角函數,有對應的f和l版本。

2、ccosh,csinh,ctanh,cacosh,casinh,catanh:復數域內的雙曲函數,有對應的f和l版本。

3、cexp,clog,cabs,cpow,csqrt:復數域內的指數、對數、絕對值、冪函數,有對應的f和l版本。

4、carg,cimag,creal,conj,cproj:獲取象限角、虛數部分、實數部分、a=x及b=-y、Riemann球上的投影,有對應的f和l版本。

代碼:

#include<stdio.h>
#include<complex.h>
int main()  
{
    double complex cmp = 1.3 + 2.3*I;
    printf("%f + %fi\n", creal(cmp), cimag(cmp));
    return 0;  
}  

2.指定初始化(Designated Initializers)

在初始化結構體和數組時,可以通過指定具體成員名或數組下標來賦初值

要指定數組的索引對應的值,可以在相應的元素值前使用‘[index] =’,index必須是常量表達式例如:

int a[6] = { [4] = 29, [2] = 15 };

等價於:

 int a[6] = { 0, 0, 15, 0, 29, 0 };

還可以向下面這樣初始化:

int a[10] = { [1] = 1, [8 ... 9] = 10 };

這樣可以只初始化a[1], a[8], a[9]三個元素,其他元素的值為0,等價於:

int a[10] = {0, 1, 0, 0, 0, 0, 0, 0, 10, 10};

對於結構體,指定成員名初始化可以使用‘.fieldname=’,例如:

 struct point { int x, y; };

接下來初始化:

struct point p = { .y = yvalue, .x = xvalue };  // 等價於 struct point p = { xvalue, yvalue };

還可以使用冒號:

struct point p = { y: yvalue, x: xvalue };

當然也可以用在union中:

union foo { int i; double d; };
union foo f = { .d = 4 };

3.變長數組(Variable Length Arrays)

C99允許可以定義一個長度為變量的數組(這個數組的長度可以到運行時才決定)

FILE * concat_fopen (char *s1, char *s2, char *mode) { char str[strlen (s1) + strlen (s2) + 1]; strcpy (str, s1); strcat (str, s2); return fopen (str, mode); } GNU示例代碼

也可以在結構體或是聯合中使用VLA:

void foo (int n)
{
      struct S { int x[n]; };
 }

你可以使用alloca函數實現類似的功能,但是alloca函數並不是都實現,從另一角度而言,VLA更加的優秀

也可以使用VLA作函數參數:

struct entry
tester (int len, char data[len][len])
{
       /* ... */
}

當然也可以後傳len

struct entry
tester (int len; char data[len][len], int len)  //注意分號
{
       /* ... */
}

示例代碼:

#include<stdio.h>
void func(int n)
{
    int vla[n];
    printf("%d\n", sizeof(vla));
}
int main()  
{
    func(4);
    return 0;  
}  

4.單行注釋

gcc支持像C++風格的注釋,以‘//’開頭直到一行的結束,很多其他支持C99的C編譯器都支持,但是c99之前的版本有可能不支持

5.柔性數組成員(Flexible Array Members)

 參見《C語言柔性數組》一文

6.long long類型

C99支持64位整型,使用long long int 或使用unsigned long long int,將整型常量聲明為long long int,在整數的後面加上‘LL’,若為unsigned long long int,則加上‘ULL’

7.inline函數

c/c++中的inline,使用在函數聲明處,表示程序員請求編譯器在此函數的被調用處將此函數實現插入,而不是像普通函數那樣生成調用代碼(申請是否有效取決於編譯器)。一般地說,這樣作的優點是省掉了調用函數的開銷;缺點則是可能會增加代所生成目標代碼的尺寸

實際上,即使沒有手工指定inline函數,編譯器一般還會選擇一些代碼量較小但使用頻繁的函數作為inline函數,以此作為性能優化的途徑之一。

和帶參宏定義(Parameterized Macro)相比,具備以下優點:

  • 參數類型檢查:宏定義中所使用的參數僅僅是在宏定義中被替換,不進行任何的類型檢查
  • 返回值:宏定義中無法使用return返回
  • 便於調試

示例代碼:

static inline int
inc (int *a)
{
       return (*a)++;
}

8.bool類型

記得以前都是自己寫#define TRUE 1, #define FALSE  0 或者 enum boolean之類的宏,現在可以使用<stdbool.h>的bool類型啦

9.復合常量(Compound Literals)

簡單來說復合常量就是允許你定義一個匿名的結構體或數組變量。如:

struct foo {int a; char b[2];} structure;
structure = ((struct foo) {x + y, 'a', 0});

等價於:

{
     struct foo temp = {x + y, 'a', 0};
     structure = temp;
}

也可以創建一個數組:

char **foo = (char *[]) { "x", "y", "z" };

更多實例:

static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};
//等價於下面的代碼:
static struct foo x = {1, 'a', 'b'};
static int y[] = {1, 2, 3};
static int z[] = {1, 0, 0};

10.for循環變量初始化(for loop intializers)

C99引入了C++中的for循環變量初始化方式:

for(int i = 0; i < 10; ++i) {
  ...;
}

除了寫起來方便以外,循環變量的生存周期也被最小化了。這也順便杜絕了那種把循環變量帶到循環外頭繼續用的惡習

11.C99新增頭文件

C89中標准的頭文件:
  <assert.h>             定義宏assert()
  <ctype.h>              字符處理
  <errno.h>              錯誤報告
  <float.h>               定義與實現相關的浮點值勤
  <limits.h>              定義與實現相關的各種極限值
  <locale.h>              支持函數setlocale()
  <math.h>              數學函數庫使用的各種定義
  <setjmp.h>           支持非局部跳轉
  <signal.h>             定義信號值
  <stdarg.h>            支持可變長度的參數列表
  <stddef.h>            定義常用常數
  <stdio.h>              支持文件輸入和輸出
  <stdlib.h>             其他各種聲明
  <string.h>             字符串函數
  <time.h>               支持系統時間函數

C99新增的頭文件
  <complex.h>          支持復雜算法
  <fenv.h>               給出對浮點狀態標記和浮點環境的其他方面的訪問
  <inttypes.h>          定義標准的、可移植的整型類型集合,也支持處理最大寬度整數的函數
  <iso646.h>            首先在此1995年第一次修訂時引進,用於定義對應各種運算符的宏
  <stdbool.h>           支持布爾數據類型類型,定義宏bool,以便兼容於C++
  <stdint.h>             定義標准的、可移植的整型類型集合,該文件包含在<inttypes.h>中
  <tgmath.h>           定義一般類型的浮點宏
  <wchar.h>             首先在1995年第一次修訂時引進,用於支持多字節和寬字節函數
  <wctype.h>           首先在1995年第一次修訂時引進,用於支持多字節和寬字節分類函數

注意:還有一些新特性未總結進來,待充分理解實踐之後將陸續補充

參考資料

https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved