?? 第2章 變量和數據存儲.txt
字號:
for(f=first; f<last; f+=small)
;
你甚至可以預先算出循環次數,然后通過這個整數進行循環計數:
float f;
int count=(last-first)/small;
for(f=first;count-->0;f+=small)
;
請參見:
2.11 對不同類型的變量進行算術運算會有問題嗎?
2.10 怎樣判斷一個數字型變量可以容納的最大值?
要判斷某種特定類型可以容納的最大值或最小值,一種簡便的方法是使用ANSI標準頭文件limits.h中的預定義值。該文件包含一些很有用的常量,它們定義了各種類型所能容納的值,下表列出了這些常量:
----------------------------------------------------------------
常 量 描 述
----------------------------------------------------------------
CHAR—BIT char的位數(bit)
CHAR—MAX char的十進制整數最大值
CHAR—MIN char的十進制整數最小值
MB—LEN—MAX 多字節字符的最大字節(byte)數
INT—MAX int的十進制最大值
INT—MIN int的十進制最小值
LONG—MAX long的十進制最大值
LONG—MIN long的十進制最小值
SCHAR—MAX signedchar的十進制整數最大值
SCHAR—MIN signedchar的十進制整數最小值
SHRT—MIN short的十進制最小值
SHRT—MAX short的十進制最大值
UCHAR—MAX unsignedchar的十進制整數最大值
UINT—MAX unsignedint的十進制最大值
ULONG—MAX unsignedlongint的十進制最大值
USHRT—MAX unsignedshortint的十進制最大值
-----------------------------------------------------------------
對于整數類型,在使用2的補碼運算的機器(你將使用的機器幾乎都屬此類)上,一個有符號類型可以容納的數字范圍為-2位數-1到(+2位數-1-1),一個無符號類型可以容納的數字范圍為0到(+2位數-1)。例如,一個16位有符號整數可以容納的數字范圍為--215(即-32768)到(+215-1)(即+32767)。
請參見:
10.1用什么方法存儲標志(flag)效率最高?
10.2什么是“位屏幕(bitmasking)”?
10.6 16位和32位的數是怎樣存儲的?
2.11 對不同類型的變量進行算術運算會有問題嗎?
C有三類固有的數據類型:指針類型、整數類型和浮點類型;
指針類型的運算限制最嚴,只限于以下兩種運算:
- 兩個指針相減,僅在兩個指針指向同一數組中的元素時有效。運算結果與對應于兩個指針的數組下標相減的結果相同。
+ 指針和整數類型相加。運算結果為一個指針,該指針與原指針之間相距n個元素,n就是與原指針相加的整數。
浮點類型包括float,double和longdouble這三種固有類型。整數類型包括char,unsigned char,short,unsigned short,int,unsigned int,long和unsigned long。對這些類型都可進行以下4種算術運算:
+ 加
- 減
* 乘
/ 除
對整數類型不僅可以進行上述4種運算,還可進行以下幾種運算:
% 取模或求余
>> 右移
<< 左移
& 按位與
| 按位或
^ 按位異或
! 邏輯非
~ 取反
盡管C允許你使用“混合模式”的表達式(包含不同類型的算術表達式),但是,在進行運算之前,它會把不同的類型轉換成同一類型(前面提到的指針運算除外)。這種自動轉換類型的過程被稱為“運算符升級(operator promotion)”。
請參見:
2.12什么是運算符升級(operatorpromotion)?
2. 12 什么是運算符升級(operatorpromotion)?
當兩個不同類型的運算分量(operand)進行運算時,它們會被轉換為能容納它們的最小的類型,并且運算結果也是這種類型。下表列出了其中的規則,在應用這些規則時,你應該從表的頂端開始往下尋找,直到找到第一條適用的規則。
-------------------------------------------------------------
運算分量1 運算分量2 轉換結果
-------------------------------------------------------------
long double 其它任何類型 long double
double 任何更小的類型 double
float 任何更小的類 float
unsigned long 任何整數類 unsigned long
long unsigned>LONG_MAX unsigned long
long 任何更小的類型 long
unsigned 任何有符號類型 unsigned
-------------------------------------------------------------
下面的程序中就有幾個運算符升級的例子。變量n被賦值為3/4,因為3和4都是整數,所以先進行整數除法運算,結果為整數0。變量f2被賦值為3/4.0,因為4.0是一個float類型,所以整數3也被轉換為float類型,結果為float類型0.75。
#include <stdio.h>
main ()
{
float f1 = 3/4;
float f2 = 3/4.0
printf("3/4== %g or %g depending on the type used. \n",f1, f2);
}
請參見:
2.11對不同類型的變量進行算術運算會有問題嗎?
2.13什么時候應該使用類型強制轉換(typecast)?
2.13 什么時候應該使用類型強制轉換(typecast)?
在兩種情況下需要使用類型強制轉換。第一種情況是改變運算分量的類型,從而使運算能正確地進行。下面的程序與2.12中的例子相似,但有不同之處。變量n被賦值為整數i除以整數j的結果,因為是整數相除,所以結果為0。變量f2也被賦值為i除以j的結果,但本例通過(float)類型強制轉換把i轉換成一個float類型,因此執行的是浮點數除法運算(見2.11),結果為0.75。
#include <stdio.h>
main ( )
{
int i = 3;
int j = 4
float f1 =i/j;
float f2= (float) i/j;
printf("3/4== %g or %g depending on the type used. \n",f1, f2);
}
第二種情況是在指針類型和void * 類型之間進行強制轉換,從而與期望或返回void指針的函數進行正確的交接。例如,下述語句就把函數malloc()的返回值強制轉換為一個指向foo結構的指針:
struct foo *p=(struct foo *)malloc(sizeof(struct foo));
請參見:
2.6什么時候應該使用volatile修飾符?
2.8什么時候應該使用const修飾符?
2.11對不同類型的變量進行算術運算會有問題嗎?
2.12 什么是運算符升級(operator promotion)?
2.14 什么時候不應該使用類型強制轉換(typecast)?
7.5 什么是void指針?
7.6 什么時候使用void指針?
7.21 什么是堆(heap)?
7.27 可以對void指針進行算術運算嗎?
2.14 什么時候不應該使用類型強制轉換(typecast)?
不應該對用const或volatile說明了的對象進行類型強制轉換,否則程序就不能正確運行。
不應該用類型強制轉換把指向一種結構類型或數據類型的指針轉換成指向另一種結構類型或數據類型的指針。在極少數需要進行這種類型強制轉換的情況下,用共用體(union)來存放有關數據能更清楚地表達程序員的意圖。
請參見:
2. 6什么時候應該使用volatile修飾符?
2. 8什么時候應該使用const修飾符?
2. 15 可以在頭文件中說明或定義變量嗎?
被多個文件存取的全局變量可以并且應該在一個頭文件中說明,并且必須在一個源文件中定義。變量不應該在頭文件中定義,因為一個頭文件可能被多個源文件包含,而這將導致變量被多次定義。如果變量的初始化只發生一次,ANSIC標準允許變量有多次外部定義;但是,這樣做沒有任何好處,因此最好避免這樣做,以使程序有更強的可移植性。
注意:變量的說明和定義是兩個不同的概念,在2.16中將講解兩者之間的區別。
僅供一個文件使用的“全局”變量應該被說明為static,而且不應該出現在頭文件中。
請參見:
2. 16 說明一個變量和定義一個變量有什么區別?
2. 17 可以在頭文件中說明static變量嗎?
2.16 說明一個變量和定義一個變量有什么區別?
說明一個變量意味著向編譯程序描述變量的類型,但并不為變量分配存儲空間。定義一個變量意味著在說明變量的同時還要為變量分配存儲空間。在定義一個變量的同時還可以對變量進行初始化。下例說明了一個變量和一個結構,定義了兩個變量,其中一個定義帶初始化:
extern int decll; / * this is a declaration * /
struct decl2 {
int member;
} ; / * this just declares the type--no variable mentioned * /
int def1 = 8; / * this is a definition * /
int def2; / * this is a definition * /
換句話說,說明一個變量相當于告訴編譯程序“在程序的某個位置將用到一個變量,這里給出了它的名稱和類型”,定義一個變量則相當于告訴編譯程序“具有這個名稱和這種類型的變量就在這里”。
一個變量可以被說明許多次,但只能被定義一次。因此,不應該在頭文件中定義變量,因為一個頭文件可能會被一個程序的許多源文件所包含。
請參見;
2.17可以在頭文件中說明static變量嗎?
2.17 可以在頭文件中說明static變量嗎?
如果說明了一個static變量,就必須在同一個文件中定義該變量(因為存儲類型修飾符static和extern是互斥的)。你可以在頭文件中定義一個static變量,但這會使包含該頭文件的源文件都得到該變量的一份私有拷貝,而這通常不是你想得到的結果。
請參見:
2.16 說明一個變量和定義一個變量有什么區別?
2.18 用const說明常量有什么好處?
使用關鍵字const有兩個好處;第一,如果編譯程序知道一個變量的值不會改變,編譯程.序就能對程序進行優化;第二,編譯程序會試圖保證該變量的值不會因為程序員的疏忽而被改變。
當然,用#define來定義常量也有同樣的好處。用const而不用#define來定義常量的原因是const變量可以是任何類型(如結構,而用#define定義的常量不能表示結構)。此外,const變量是真正的變量,它有可供使用的地址,并且該地址是唯一的(有些編譯程序在每次使用用#define定義的字符串時都會生成一份新的拷貝,見9.9)。
請參見:
2.7 一個變量可以同時被說明為const和volatile嗎?
2.8 什么時候應該使用const修飾符?
2.14 什么時候不應該使用類型強制轉換(typecast)?
9.9 字符串和數組有什么不同?
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -