[英]Variadic function (va_arg) doesn't work with float, while printf does? What the difference is?
我碰巧在兩年的這個問題中遇到了類似的情況:
有人說,當我們稱之為的時候,問題是促使浮動加倍
va_arg(arg, float)
我的問題是在這篇文章的最后,但首先讓我們來看看@ Jack在上面鏈接的問題下面的答案:
#include <stdio.h>
#include <stdarg.h>
void foo(int n, ...)
{
va_list vl;
va_start(vl, n);
int c;
double val;
for(c = 0; c < n; c++) {
val = va_arg(vl, double);
printf("%f\n", val);
}
va_end(vl);
}
int main(void)
{
foo(2, 3.3f, 4.4f);
return 0;
}
輸出:
3.300000
4.400000
現在,如果我們將val = va_arg(vl, double)
更改為val = va_arg(vl, float)
,我們將得到(至少我進入MSVS 2012):
36893488147419103000.000000
2.162500
我們現在回答我的問題。
在這個主題中: C / C ++ va_list沒有正確地返回參數最多的投票答案,並且它的評論說printf
也將 float
的提升為double
。
但有什么區別? 如果它們都將float
提升為double
,為什么printf
正確地寫入值,而va_arg
會給我們這樣一個鼻子惡魔?
它不是printf
,它將float參數提升為double
,它是編譯器 。 換句話說,當你的va_arg
或printf
或任何其他具有可變參數數量的函數獲得控件時,所有的float
都已被提升為double
s; 原始float
不可用於檢索。
之間的差printf
和va_arg
是printf
遵循由標准設立的規則,並請求一個提升的類型(即,參數double
)時,看到在格式字符串對應的格式說明。 因此,它成功地獲得了一個double
的float
值,並產生了所需的輸出。
另一方面,當va_arg
調用val = va_arg(vl, float)
它會忽略促銷規則,並獲得無效的表示形式。
變量參數函數的參數獲得特殊的促銷規則。
這里相關的一個是將float作為變量參數傳遞給double。 這意味着您不能將參數作為float提取,因為它已作為double傳遞。 這是由編譯器完成的,它與printf
無關。
這意味着代碼val = va_arg(vl, float)
無效,因為參數不是float,它是double。 如果你真的需要將傳入的值作為浮點數來處理,那么你最多可以做到
float val = (float) va_arg(vl, double)
請注意,printf的%f
說明符期望參數類型為double
,而不是float
printf
不接受float
類型的參數。
例如, "%f"
格式說明符需要double
類型的參數。 "%Lf"
需要long double
類型的參數。 沒有格式需要一個float
類型的參數(無論如何都會提升為double
,而不是printf
本身,而只是因為調用variadic函數的語義)。
因此假設printf
是用C實現的,並且它使用<stdarg.h>
機制來讀取它的參數,在printf
的實現中沒有為float
類型調用va_arg()
。
任何嘗試為類型float
調用va_arg()
可變函數都將具有未定義的行為,因為這樣的函數不能有float
參數。 printf
有效,因為它沒有這樣做。
但有什么區別? 如果它們都將
float
提升為double
,為什么printf
正確地寫入值,而va_arg
會給我們這樣一個鼻子惡魔?
除了事實(在問題本身中說明)之外,沒有區別, printf
的編碼方式是將float
視為double
。 換句話說,在printf
內部的某個地方,當格式字符串包含應該有浮點數的信息時,該函數會執行va_arg(vl, double)
,就像你一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.