簡體   English   中英

為什么 printf 的 hh 和 h 長度修飾符存在?

[英]Why does printf's hh and h length modifiers exist?

在可變參數函數中,會發生默認參數提升。

6.5.2.2.6 如果表示被調用函數的表達式的類型不包含原型,則對每個參數執行整數提升,而float類型的參數提升為double 這些稱為默認參數提升 [...]

6.5.2.2.7 [...] 函數原型聲明符中的省略號會導致參數類型轉換在最后一個聲明的參數之后停止。 默認參數提升是在尾隨參數上執行的。

所以,

signed char c = 123;
int         i = 123;
float       f = 123;
double      d = 123;

printf("%d\n", i);   // ok
printf("%d\n", c);   // ok, even though %d expects int.
printf("%f\n", d);   // ok
printf("%f\n", f);   // ok, even though %f expects double.

那么為什么有一個用於char ( hh ) 和short ( h ) 的printf長度修飾符呢?


章節編號參見 N2176。

考慮這個例子:

#include <stdio.h>
int main(void)
{
    unsigned short x = 32770;
    printf("%d\n", x) ;  // (1)
    printf("%u\n", x) ;  // (2)
}

在典型的 16 位實現中,默認參數提升將unsigned short變為unsigned int ,而在典型的 32 位實現中, unsigned short變為int

所以在 16 位系統上 (1) 是 UB 並且 (2) 是正確的,但是在 32 位系統上,(1) 是正確的和 (2) 可以爭論是正確還是 UB。

使用%hu打印x適用於所有系統,您不必考慮這些問題。

可以為sizeof(int) == 1系統上的char構造一個類似的示例。

這是為了向后兼容。

在 C89 標准的草案版本中,使用%x格式說明符打印有符號的intshortchar不是未定義的行為

d, i, o, u, x, X int 參數轉換為有符號十進制( d 或 i )、無符號八進制( o )、無符號十進制( u )或無符號十六進制表示法( x 或 X ); 字母 abcdef 用於 x 轉換,字母 ABCDEF 用於 X 轉換。 精度指定出現的最小位數; 如果被轉換的值可以用更少的數字表示,它將用前導零擴展。 默認精度為 1。使用顯式精度為零的零值轉換的結果是沒有字符。

這似乎證明了預先標准化的 C,使用格式說明符(例如%x表示有符號值)是一種現有做法,因此可能存在使用hhh長度修飾符的預先存在的代碼庫。

如果沒有hhh長度修飾符,如果使用簡單的%X格式說明符打印,則位模式為0xFFsigned char值將在 32 位int系統上打印為0xFFFFFFFF

特別是關於hh說明符,它在 C99 中明確添加,以便利用stdint.h / inttypes.h中所有默認固定大小類型的打印。 C99 使int_leastn_t類型從 8 到 64 是強制性的,因此需要相應的格式說明符。

來自 C99 基本原理 5.10, §7.19.6.1 ( fprintf ):

%hh%ll長度修飾符是在 C99 中添加的(參見 §7.19.6.2)。

§7.19.6.2 ( fscanf ):

C99 的一個新特性:在 C99 中添加了hhll長度修飾符。 ll支持新的 long long int 類型。 hh增加了將字符類型與所有其他整數類型一樣對待的能力; 這對於在<inttypes.h>中實現諸如SCNd8宏很有用(參見 7.18)。

在 C99 之前,只有dhl用於打印整數類型。 例如,在 C99 中,傳統實現可以將inttypes.h說明符定義為:

#define SCNi8   hh
#define SCNi16   h
#define SCNi32   d
#define SCNi64  ll

現在默認參數提升成為printf / scanf實現的inttypes.h ,而不是inttypes.h實現。

它們不是用於printf()使用,而是用於scanf()能夠使用對short整數和char整數的引用。 為了統一性和完整性,它們被printf()函數接受,但它們是不可區分的,因為對於所有類型為shortchar整數值的參數, printf()的 vaarg 參數都被提升為int 所以它們在printf()是等價的,但在scanf()和朋友中不是。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM