簡體   English   中英

為什么printf中相同表達式的輸出與cout不同?

[英]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,因為所有操作數都是整數常量,但是您指定它是printfdouble ,因此它將被錯誤地處理。 另一方面,如果您在表達式的除法部分中使用了浮點常量 ,例如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 :: coutoperator <<具有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 浮點支持未加載

必要的浮點庫沒有鏈接。 通過檢查以下可能的原因來解決問題

  1. 該程序是編譯或鏈接的選項,如/ FPi87,需要一個協處理器,但該程序是在沒有安裝協處理器的機器上運行的。
  2. printf_s或scanf_s函數的格式字符串包含浮點格式規范,程序不包含任何浮點值或變量。
  3. 編譯器通過僅在必要時加載浮點支持來最小化程序的大小。 編譯器無法檢測格式字符串中的浮點格式規范,因此它不會加載必要的浮點例程。
  4. 使用浮點參數對應浮點格式規范,或在程序中的其他位置執行浮點賦值。 這會導致加載浮點支持。
  5. 在混合語言程序中,在鏈接程序時,在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.

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