[英]Why does this output of the same expression from printf differ from cout?
我正在使用Visual C ++ 2012並從命令行編譯以下文件:
#include <stdio.h>
int main()
{
printf("%.5f", 18/4+18%4);
return 0;
}
鏈接MSVCRT.LIB而不是LIBCMT以避免運行時錯誤R6002。
對於此程序,輸出的值為0.00000。
但是,如果我在C ++中執行完全相同的操作
#include <iostream>
using namespace std;
int main()
{
cout << 18/4+18%4 << endl;
return 0;
}
現在,它打印出6,就像它應該的那樣。
有什么不同? 它與語言本身(C vs C ++)或輸出方法(cout vs printf)有關,還是只是與MSVC的怪癖?
表達式18/4+18%4
計算為int
,並且您正在請求浮點數。 你應該總是在啟用警告的情況下進行編譯,並注意它們(他們說警告是等待發生的錯誤 ,並且它們是正確的)。
這就是我的編譯器(GCC 4.8.1)告訴我的(甚至沒有強制執行-Wall
):
warning: format ‘%.5f’ expects type ‘double’, but argument 2 has type ‘int’
另一方面, std::cout<<
操作能夠推斷出表達式的類型並將其正確地流式傳輸到屏幕上。
C函數正在傳遞一個整數,但是你告訴它(使用%f
)期望一個雙精度浮點數,所以它失敗了。 C ++函數知道它正在傳遞一個整數,因此它可以正常工作。
在C示例中,此表達式18/4+18%4
將計算為int,因為所有操作數都是整數常量,但是您指定它是printf
的double ,因此它將被錯誤地處理。 另一方面,如果您在表達式的除法部分中使用了浮點常量 ,例如18.0/4+18%4
則整個表達式將計算為double 。 或者,您也可以在格式說明符中使用"%d"
。
這也是未定義的行為 ,錯誤地指定printf
的格式,這也說明了為什么構建警告很重要,使用gcc -Wall
我收到以下警告( 請參見實時 ):
warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’
在C ++中, std :: cout的operator <<具有int
的重載,因此在這種情況下將調用它。 我們可以看到這個重載是C ++草案標准所要求的許多其他重載,在27.7.3.1
節類模板basic_ostream中我們找到以下運算符聲明:
basic_ostream<charT,traits>& operator<<(int n);
為了完整起見,回到未定義的行為,第7.19.6.1
節中的C99草案標准 printf
的部分引用的fprintf函數返回格式字符串第9段說:
如果轉換規范無效,則行為未定義。[...]
表達方式
18 / 4 + 18 % 4
評估為int 。
但printf格式字符串“%。5f”需要加倍。
使用c ++和ostreams,語言可以自動確定輸出類型。
只需將您的C代碼更改為以下內容:
#include <stdio.h>
int main()
{
printf("%d", 18 / 4 + 18 % 4);
return 0;
}
其他人已正確指出printf()語句中的int / double不匹配。 我只想評論你的聲明,“鏈接MSVCRT.LIB而不是LIBCMT,以避免運行時錯誤R6002。” 這個簡單的程序不應過度對運行時環境征稅,因此像這樣的運行時錯誤應該是代碼中未定義行為的紅色標志。
一個快速的谷歌“MSVCRT R6002”說:
C運行時錯誤R6002 浮點支持未加載
必要的浮點庫沒有鏈接。 通過檢查以下可能的原因來解決問題
- 該程序是編譯或鏈接的選項,如/ FPi87,需要一個協處理器,但該程序是在沒有安裝協處理器的機器上運行的。
- printf_s或scanf_s函數的格式字符串包含浮點格式規范,程序不包含任何浮點值或變量。
- 編譯器通過僅在必要時加載浮點支持來最小化程序的大小。 編譯器無法檢測格式字符串中的浮點格式規范,因此它不會加載必要的浮點例程。
- 使用浮點參數對應浮點格式規范,或在程序中的其他位置執行浮點賦值。 這會導致加載浮點支持。
- 在混合語言程序中,在鏈接程序時,在FORTRAN庫之前指定了C庫。 最后重新鏈接並指定C庫。
當然,這里的教訓是你應該密切關注編譯器和運行時警告和錯誤。 如有疑問,請始終假設問題出在您的代碼中,而不是編譯器中。
在C中,因為你在printf格式說明符中明確指定浮點(“%f”),所以它期望浮點參數。 但你給它一個“int”參數,因此問題。
根據您的目的,您可以:
1)將您的(否則為整數 )表達式轉換為float
和/或
2)使用setprecision在COUT流,就像你用C使用“%.5f”:
#include <iostream>
using namespace std;
int main()
{
float x = 18/4+18%4;
std::cout << std::setprecision(5) << x << endl;
return 0;
}
3)如果你想要整數,使用printf ("%d", 18/4+18%4);
如果你想要相同的行為(和響應),你最好編碼
printf("%d\n", 18/4 + 18%4);
獲取int響應而不是浮點響應。 你將獲得與<<
operator selected is相同的結果
ostream& std::operator<<(ostream&, const int);
否則,您可以明確使用
printf("%.5f\n", (double)(18/4 + 18%4));
獲得6.00000
結果。
讓您的一個數字成為浮點值:
#include <stdio.h>
int main()
{
printf("%.0f", 18/4.0+18%4);
return 0;
}
一種可能的替代方法是,對文字(或表達式本身)進行類型轉換:
#include <stdio.h>
int main(void)
{
printf("%.5f", (float)18/4+18%4);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.