[英]char type in va_arg
我有以下函數將傳遞的參數寫入二進制文件。
void writeFile(FILE *fp, const int numOfChars, ...)
{
va_list ap;
va_start(ap, numOfChars);
for(int i = 0; i < numOfChars; i++)
{
const char c = va_arg(ap, char);
putc(c, fp);
}
va_end(ap);
}
編譯后,我從編譯器收到以下警告
warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg
has undefined behavior because arguments will be promoted to 'int' [- Wvarargs]
現在據我了解,C想要將char類型提升為int。 為什么C想要這樣做? 第二,是將int轉換回char的最佳解決方案嗎?
現在據我了解,C想要將char類型提升為int。 為什么C想要這樣做?
因為這就是標准所說的。 如果將轉換等級小於int
的整數值(例如char
, bool
或short
)傳遞給采用可變數量參數的函數,則將其轉換為int
。 據推測,其原因在於其性能,其中(實際上,現在通常仍然是如此)更好地傳遞與機器字邊界對齊的值。
第二,是將int轉換回char的最佳解決方案嗎?
是的,但你甚至不需要強制轉換,隱式轉換會:
char ch = va_arg(ap, int);
變量函數經過特殊處理。
對於非可變函數,原型(聲明)指定所有參數的類型。 參數可以是任何(非數組,非函數)類型 - 包括比int
窄的類型。
對於可變函數,編譯器不知道與, ...
對應的參數類型。 由於歷史原因,為了使編譯器的工作更容易,任何比int
更窄的類型的相應參數都被提升為int
或unsigned int
,並且float
類型的任何參數都被提升為double
。 (這就是為什么printf
對float
或double
參數使用相同的格式說明符。)
因此,可變參數函數不能接收 char
類型的參數。 您可以使用char
參數調用此類函數,但它將被提升為int
。
(在C的早期版本中,在引入原型之前, 所有函數都以這種方式運行。甚至C11也允許非原型聲明,其中窄參數被提升為int
, unsigned int
或double
。但是考慮到原型的存在,確實存在沒有理由編寫依賴於此類促銷的代碼 - 除了可變函數的特殊情況。)
因此,將va_arg()
接受char
作為類型參數是沒有意義的。
但是語言不禁止這樣調用va_arg()
;
實際上,描述
。 該規則在函數調用部分N1570 6.5.2.2第7段中說明: <stdarg.h>
的標准部分沒有提到參數提升
如果表示被調用函數的表達式具有包含原型的類型,則將參數隱式轉換為相應參數的類型,就像通過賦值一樣,將每個參數的類型作為其聲明的非限定版本類型。 函數原型聲明符中的省略號表示法導致參數類型轉換在最后聲明的參數之后停止。 默認參數提升是在尾隨參數上執行的。
va_arg()
宏的描述7.16.1.1說(強調添加):
如果沒有實際的下一個參數,或者type與實際的下一個參數的類型不兼容( 根據默認參數提升而提升 ),則行為是未定義的,除了以下情況:
[SNIP]
“default argument promotions”將narrow參數轉換為int
, unsigned int
或double
。 (最大值超過INT_MAX
的無符號整數類型的INT_MAX
將被提升為unsigned int
。理論上, char
可以以這種方式運行,但僅限於非常不尋常的實現。)
第二,是將int轉換回char的最佳解決方案嗎?
不,不是在這種情況下。 鑄造很少是必要的; 在大多數情況下,隱式轉換可以完成相同的工作。 在這種特殊情況下:
const char c = va_arg(ap, char);
putc(c, fp);
putc
的第一個參數已經是int
類型,所以這寫得更好:
const int c = va_arg(ap, int);
putc(c, fp);
int
值由putc
轉換為unsigned char
並寫入fp
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.