為什麼scanf()用cmd編譯可以通過,但用vs2015卻不能通過?

上圖黑色背景是我在cmd中編譯的,沒有問題,也可以執行(順便說一下,我的環境變數設置是在vs2015目錄下弄的);下圖是在vs2015中編譯的,卻報錯了,它要我將scanf()改為scanf_s(),請幫我解答一下這個問題,謝謝!

看了一下諸位的答案,發現大家都沒理解我的問題的重點:我問的是為什麼直接在cmd窗口中調用vs2015的編譯器編譯可以通過但是直接用vs2015卻不能通過。不是問為什麼要用scanf_s()


因為C語言的新標準是scanf_s


謝邀,這應該只是因為你用VS調用cl的時候加了一些參數,把類似於這種Warning當成Error了。

解決辦法應該是去把Warning調低。

然而,你為什麼不用scanf_s?

謝邀。


因為vs2015安全級別更好一些,使用scanf()函數不檢查邊界,出現出現內存泄露,如: char a[5]={""}; scanf(「%s」,a),輸入0123456789,分配5位元組,讀取了10位元組,只讀取前面一部分,後面一部分寫到了其他空間;當使用scanf_s()時,需要指定讀取大小,如char a[10],scanf_s("%s",a,10),規定讀取空間大小。也可以在vs2015中在代碼最開頭加上 #define _CRT_SECURE_NO_WARNINGS預處理去掉安全檢查。


如果你像同樣在vs2015上寫是scanf(),你應該在頭文件前面打上#pragma warning(disable:4996)


答的有點跑題,雖然在回復里說明白了,不過還是來這裡修改一下。

題主補充了問題,主要問的是為什麼在命令行狀態直接cl 3.cpp不會觸發錯誤,而在vs ide環境下會觸發。

這是因為題主用vs時是新建了一個工程來編譯這個文件的,新建的工程默認啟用了sdl檢查,也就是相當於在命令行中cl後面加了一個/sdl的參數,這個參數會對程序的要求更嚴格,所以就觸發了錯誤。

以下是關於_s函數細節的原答案

----------------------------------

其他答案說的很明白了,不加_s的函數不安全,所以微軟認為不好,所以vs里默認就強制不讓用了.那麼,我就簡單的說說為什麼不安全。

想想這樣的代碼

char s[3];
scanf("%s", s);

如果我在輸入的時候輸入我這個回答的全部文字,會發生什麼呢?s只有3個位元組的長度,剩下的文字就寫入了s後面的其他空間,這個問題叫緩衝區溢出而_s後綴的函數,會有額外的參數,用來說明緩衝區的長度.比如:

scanf_s("%s", s, 3);

差不多就是這樣,下面是一些更加細節的東西,不看也沒什麼,而且本人並非專業人士,如果內容有誤還請包含。

----------------------------------

那些被s覆蓋空間如果是廢棄的還好,如果是其他部分的變數呢,你是不是就這樣給改掉了。並且這s之外的空間還不止這麼簡單,因為在大部分電腦上,局部變數這東西,是放在一個叫棧的臨時存儲區里的,這個存儲區里不只是存s這樣的人畜無害的數據,裡面還存有跟代碼有關的東西(比如x86平台上的call子程序調用的返回地址),這意味著如果覆蓋掉了那些東西,程序的流程都可能改變。

專業人士(黑客等)可以輕而易舉的、可控的利用這種溢出來完成各種事情,這叫緩衝區溢出攻擊.常見的流程是這樣的:

1.攻擊者輸入一段包含惡意代碼的特殊文本

2.特殊文本因為過長,所以覆蓋了流程式控制制代碼。

/*比如當前子程序被調用完畢返回到上層的時候,返回的目標地就是臨時存在棧里的,特殊文本覆蓋掉了這個目標地,覆蓋成了特殊文本中惡意代碼的地址。*/

3.當前子程序正常返回時,不會察覺到返回地址已經被惡意修改了,於是返回到了惡意代碼處開始繼續執行。

4.現在你的命運如何就只能看那段惡意代碼是幹什麼的了,也許是友善的彈出一個計算器嚇你一跳,也許是盜光你的賬號刪光你的硬碟。


因為它採用了最新的安全的scanf_s(),如果題主想在vs中使用scanf()的話,可以在建立工程的時候取消"安全生命周期檢查"的對勾


#define_CRT_SECURE_NO_WARNINGS


推薦閱讀:

有那些值得學習的C/C++和Lua開發的項目源碼?
什麼是面向對象編程?它與面向過程編程的異同有哪些?
C++中為什麼有delete[]這種寫法?
關於指針數組的初始化的一個問題?
C++ string + 號返回的是右值,為什麼下面這段代碼不報錯?

TAG:編程 | C | MicrosoftVisualStudio2015 |