2014-05-23 23 views
2

我剛好有想在這個問題類似的情況由兩年:變量函數(va_arg)不能用於float,而printf呢?有什麼區別?

Variadic function (va_arg) doesn't work with float?

有消息稱,這個問題是促進浮動當我們調用之類的東西

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),我們會得到(至少我得到了2012 MSVS):

36893488147419103000.000000 
2.162500 

讓我們去到我現在的問題。

在這個話題:C/C++ va_list not returning arguments properly 大多數投票的答案,這是評論說,printf促進float年代到double的。

但有什麼區別?如果兩者都將float提升爲double,爲什麼printf正確寫入值,而va_arg爲我們提供了這樣一個鼻子惡魔?

+3

是什麼讓你認爲'printf'嘗試解析參數,它知道會被提升爲'double',如'float'? 'printf'函數總是知道'float'會被傳遞的'double'。你的功能沒有。這是不同的。 –

+0

謝謝大家的好評!現在我明白了,不僅如何運作,還有更多。 – Kusavil

回答

5

這是不是printf,它將float參數提升爲double,它是編譯器就是這樣做的。換句話說,當你的va_argprintf或任何其他帶有可變參數個數的函數獲得控制權時,所有的floats已經被提升爲doubles;原始float s不可用於檢索。

printfva_arg之間的差別在於如下printf由標準設立的規則,並請求一個提升的類型(即double)時,看到在格式字符串對應的格式指定符的參數。因此,它成功獲得double,其中float的促銷價值在其中,併產生所需的輸出。

另一方面,當va_arg調用val = va_arg(vl, float)時,它會忽略促銷規則,並返回無效表示形式。

+0

注意:如果'printf()'的參數是'char','short'或者小於'int'的任何參數,那麼這個問題就適用:需要用'va_arg()'使用'int'。 – chux

+0

非常感謝您的回答,現在我明白這裏騷動的原因是什麼。 – Kusavil

3

可變參數函數的參數獲取特殊促銷規則。

與此相關的一個是將float作爲變量參數傳遞給double。這意味着你不能將參數提取爲一個float,因爲它已經作爲double傳遞。這是由編譯器完成的,它與printf無關。

這意味着代碼val = va_arg(vl, float)無效,因爲參數不是浮點數,而是雙精度值。 如果你真的需要處理的值傳遞爲float,充其量可以做

float val = (float) va_arg(vl, double) 

注意,%f說明符的printf預計double類型的參數,而不是一個float

2

但有什麼區別?如果兩者都將float提升爲double,爲什麼printf正確寫入值,而va_arg爲我們提供了這樣一個鼻子惡魔?

有沒有區別,除了事實(在這個問題本身說明),即printf以這樣的方式對待floatdouble編碼。換句話說,在printf之內的某個地方,當格式字符串包含應該有一個浮點數的信息時,該函數的確如va_arg(vl, double)一樣。

3

printf不需要參數類型float

例如,"%f"格式說明符需要參數類型爲double"%Lf"需要long double類型的參數。沒有格式需要float類型的參數(無論如何將被升級爲double,而不是由printf本身,但僅僅是因爲調用函數的語義)。

因此,假設printf是用C實現的,它使用的<stdarg.h>機制來讀取它的參數,對於在printf實施float類型沒有va_arg()調用。

確實嘗試調用va_arg()float類型的任何可變參數函數都會有未定義的行爲,因爲這樣的函數沒有參數floatprintf的作品,因爲它不這樣做。

相關問題