[英]How can I identify an integer promotion and a demotion in C?
我正在學習 C 和 integer 提升和降級這個詞對我來說是新的。 我在 C Standard (C17) 中讀到了關於 C 類型轉換和 integer 提升的信息,但我不知道如何識別 integer 提升,我對降級一無所知。
例如,如果我有這些代碼行:
...
unsigned char x;
int y;
long int z;
int aux; //Auxiliary variable
x = 'c';
y = 1;
z = 2;
aux = x;
aux = y;
aux = z;
aux = x + y; //ZX
aux = y + z;
...
哪里有integer促銷? 因為據我所知,在用ZX
注釋的代碼行中,我有 integer 提升,但僅在那一行,但我不確定; 你能幫我澄清一下嗎?
你能舉出降級的例子嗎? 因為C標准沒有明確。
絕對不是我的專長,但讓我試試:
unsigned char x;
int y;
long int z;
int aux; //Auxiliar variable
x='c';
y=1;
z=2; // Very subtle promotion here. 2 is an int, and is promoted to long int to fill z.
aux=x; // Value of x, which is a char, is PROMOTED to int, to fill aux
aux=y; // Both left and right sides are int, no promotion/demotion
aux=z; // Z is a long int, is demoted to fill aux.
aux=x+y; // x(char) is PROMOTED for addition, to match other operand y(int)
aux=y+z; // y(int) is promoted to match longer type z(long int). The result(long int) is then demoted to match assignment aux.
我在編程時盡量不要過度依賴提升規則。
Integer promotion 是一個正式的名詞 C ,但是不存在所謂的“降級”這個正式甚至非正式的名詞。 請查看隱式類型提升規則以了解 integer 轉換等級、integer 提升和通常的算術轉換。
最接近降級的是“賦值期間的轉換”,它可以 go 從較大的類型到較小的類型,反之亦然。 如果操作數的類型不同 (6.5.16.1),這會在賦值期間發生:
在簡單賦值(=)中,將右操作數的值轉換為賦值表達式的類型,並替換存儲在左操作數指定的 object 中的值。
至於實際的轉換是如何進行的,參見C17 6.3.1.3。
關於代碼中 integer 促銷/隱式轉換的位置:
x = 'c';
賦值期間的轉換,從'c'
的類型int
到unsigned char
。
z = 2;
賦值期間的轉換,從2
的類型int
到long
。
aux = x;
賦值期間的轉換,從unsigned char
到int
。
aux = z;
賦值期間的轉換,從long
到int
。
轉換為簽名類型涉及實現定義的行為,因此如果較大的值不能適合較小的類型,則可能是一個錯誤。
aux = x + y;
通常的算術轉換,包括 integer 將x
提升為int
。
aux = y + z;
通常的算術轉換,將y
變成long
。 然后在分配期間進行轉換,轉換回int
。 同樣,這里可能存在錯誤。
(最后一個例子中的一些微妙的東西:如果y + z
會導致溢出int
而不是long
的值,溢出實際上不會發生在這里,因為加法之前的long
轉換。會有一個轉換回int
時的值損失,但僅僅是實現定義的行為而不是未定義的行為溢出。)
術語降級在 C 標准中沒有定義,它只在附件 J - 可移植性問題的 C17 標准中使用過一次,僅供參考,不是標准的規范部分。 該短語不是定義,它只是暗示在將值從一種浮點類型轉換為另一種浮點類型時可能會發生降級,大概具有較小的域:
附錄 J
(資料性的)
便攜性問題
1 本附件收集了本國際標准中出現的有關可移植性的一些信息。J.1 未指明的行為
[...]
J.2 未定義的行為
在以下情況下,行為未定義:
[...]
— 將一種真正的浮動類型降級為另一種會產生超出可表示范圍的值 (6.3.1.5)。
鏈接部分未使用該詞:
6.3.1.5 真正的浮動類型
1 將實浮點類型的值轉換為實浮點類型時,如果被轉換的值可以在新類型中准確表示,則它不變。 如果被轉換的值在可以表示但不能精確表示的值范圍內,則結果是最近的較高或最近的較低可表示值,以實現定義的方式選擇。 如果被轉換的值超出了可以表示的值范圍,則行為未定義。 一些隱式轉換的結果可以用比新類型所要求的范圍和精度更大的范圍和精度來表示(見 6.3.1.8 和 6.8.6.4)。
如僅供參考的附件中所述,降級發生在例如將double
精度值存儲到float
變量時,其值不能由float
類型表示。 在一個經典的編程測試中找到了一個典型的案例:
float amount = 0.10; // implicit conversion from double to float
沒有像C這樣的整數“降級”,但是有升職。 我相信您將晉升和降級與轉換混為一談。
當在表達式中使用小於int
的 integer 類型時,會發生integer 提升,在大多數情況下,它將提升為int
或unsigned int
。 這在C 標准的第 6.3.1.1p2 節中有詳細說明:
在可以使用 int 或 unsigned int 的表達式中,可以使用以下內容:
- object 或具有 integer 類型(
int
或unsigned int
除外)的表達式,其 integer 轉換等級小於或等於 int 和 unsigned int 的等級。_Bool
、int
、signed int
或unsigned int
類型的位域。如果 int 可以表示原始類型的所有值(受寬度限制,對於位字段),則該值將轉換為
int
; 否則,它被轉換為unsigned int
。 這些稱為integer 促銷活動。 integer 促銷活動未改變所有其他類型。
這與轉換不同,轉換發生在任何類型更改為另一種類型時,無論新類型比原始類型大還是小。
現在將其應用於您的示例代碼:
x = 'c';
賦值運算符將右操作數轉換為左操作數的類型。 字符常量的類型為int
,因此賦值執行從int
到unsigned char
的轉換
y = 1;
沒有后綴的十進制 integer 常量的類型是int
,所以這里沒有轉換或提升。
z = 2;
此賦值執行從int
到long int
的轉換。
aux = x;
此賦值執行從unsigned char
到int
的轉換。
aux = y;
雙方有相同的類型,所以沒有轉換。
aux = z;
此賦值執行從long int
到int
的轉換。
aux = x + y; //ZX
首先看+
運算符,左操作數x
首先被提升為int
。 兩個操作數現在都具有類型int
,因此沒有其他轉換,並且x + y
的結果具有類型int
。 對於分配,雙方具有相同的類型,因此不應用任何轉換
aux = y + z;
首先查看+
運算符,沒有提升,因為兩個操作數至少與int
一樣大。 因為左操作數是int
而右操作數是long int
,所以左操作數被轉換為long int
並且y + z
的結果具有long int
類型。 然后將此結果轉換為int
以分配給aux
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.