天天看點

C\C++中int、double等資料類型範圍的了解

C \ C++中整型資料都是有資料範圍的,對溢出的資料處理機制一般是資料值和資料範圍值進行求模處理,求模可以這麼了解,資料描述是一個資料描述範圍最小值到最大值的一個閉環循環,求模後的值會仍在這個閉環範圍内,例如鐘表,可用1~12來一個閉環來描述,13則就是從新回到1(13 % 12)。

在C\C++中,一個整型資料val,其目前類型下的描述值可用如下公式計算:

描述值 = (val - 目前類型最小值) % 資料範圍 + (目前類型最小值)

這個計算對于資料溢出和不溢出都是适用的。

以short 和 unsigned short類型來說明。

(1)short int資料類型

short資料占用2個位元組,則資料範圍為-32768~32767,共計65536個數,則一個short val,其實際描述值realVal為

realVal = (val - (-32768)) % 65536 + (-32768)

示例代碼:

short sia = -;
    short sib = (- + ) %  - ;

    printf("not overflow\n");
    printf("sia = %hd\n", sia);
    printf("sib = %hd\n", sib);

    sia = -;
    sib = (- + ) %  - ;

    printf("\noverflow\n");
    printf("sia = %hd\n", sia);
    printf("sib = %hd\n", sib);

    sia = ;
    sib = ( + ) %  - ;

    printf("\noverflow\n");
    printf("sia = %hd\n", sia);
    printf("sib = %hd\n", sib);
           

運作結果:

C\C++中int、double等資料類型範圍的了解

說明:

(1)在指派操作時,如

sia = -32769

,-32769是先作為一個常量值存放在記憶體中,這個數值是沒有越界的概念的,就是二進制值,隻是在指派操作時才進行了對應的資料轉換;

(2)從運作結果可見,該處理機制對資料溢出和不溢出得到的結果都是适用的;

(3)聯想資料閉環循環,如程式中32768,超過short型上限,其溢出一個數,作為一個資料閉環,則直接跳轉到了-32768,也就是short型下限值。

(2)unsigned short資料類型

處理機制同上,對于一個unsigned short資料val,實際存儲值realVal為

realVal = (val - 0) % 65536 + 0

示例代碼:

unsigned short uia = ;
    unsigned short uib =  % ;
    printf("not overflow\n");
    printf("uia = %hu\n", uia);
    printf("uib = %hu\n", uib);

    uia = ;
    uib =  % ;
    printf("\noverflow\n");
    printf("uia = %hu\n", uia);
    printf("uib = %hu\n", uib);
           

運作結果:

C\C++中int、double等資料類型範圍的了解

(3)double和float的資料精度

double和float資料有精度範圍,對于float和double類型的精度範圍和描述方式,可參考下面的兩篇文章:

http://www.linuxidc.com/Linux/2012-07/65987.htm

http://blog.sina.com.cn/s/blog_6ebd49350101gdgo.html

一旦超過精度範圍,就不能精确的描述該資料,不同的處理器對不能精确描述的部分的處理機制可能是不同的,這也就導緻了在不同的平台上為什麼一套代碼的運作結果會不一緻,最近在調試程式時,出現PC上(intel處理器)和手機中(arm處理器)中運作結果不一緻的現象。在單步調試時發現在超出資料精度後的處理機制不一緻而導緻的。

(4)資料類型轉換

當unsigned型資料類型之間轉換時,低範圍向高範圍轉換時不會出現溢出現象,高範圍向低範圍轉換時,則可以按照上述方式得到要轉換的值。

當unsigned和signed類型之間進行轉換時,正數部分的轉換同上,由負數轉向unsigned型,也就是直接讀取記憶體中的資料,然後進行格式轉換即可,例如

short val = -;
unsigned short uval = val;
unsigned int uival = val;
           

資料存儲是以反碼表示,short型-1的表示為1111 1111 1111 1111(補碼形式),轉換為unsigned short時不需要擴充位元組,直接讀取位元組内容即為1111 1111 1111 1111,這裡沒有符号位,則uval = 65535,同理轉換為unsigned int時,需要擴充位元組,為了盡量避免轉換錯誤會先進行同類型資料轉換,即先轉成int,然後在轉成unsigned int,有如下處理過程:

int temp = val;
unsigned short uval = temp;
           

轉成int時會擴充位元組,擴充為0xFFFFFFFF,在轉換為unsigned short時,則uval = 4294967295。

上述轉換也可以用上面的公式來計算得到

示例代碼:

short iSVal = -;
    unsigned uSVal = (- - ) %  + ;
    unsigned uVal = (- - ) %  + ;

    printf("iSVal = %hd\n\n", iSVal);
    printf("iSVal change unsigned short val %hu\n", iSVal);
    printf("uSVal = %hu\n", uSVal);

    printf("\niSVal change unsigned int val %u\n", iSVal);
    printf("uVal = %u\n", uVal);
           

運作結果:

C\C++中int、double等資料類型範圍的了解

可見在進行類型轉換時均可以使用上面的公式來得到結果!不過不建議unsigned和signed之間進行類型轉換。

(5)其他

不同處理器之間可能對資料越界問題的處理機制可能會不一樣,前面說過arm和intel對float和double型資料超過其精度範圍的資料處理機制就不同,同樣在調試中發現arm處理器對int資料越界後會将值設定為int型最大值,這個比較奇怪了。

是以在程式設計時還是要預估資料範圍來設定資料類型,以防止程式運作錯誤,必要時要提升資料範圍。

繼續閱讀