C_and_CPP 板


LINE

首先,我複議 lwecloud 的說法:都已經 2023 年,Windows 都是 NT-based 的了, 不要再用 MBSC/ANSI 了。 你要做的事,不是把 compiler option 改成 MBSC,而是要想為什麼你在 Unicode 下 編譯/執行有問題? ※ 引述《xavier13540 (柊 四千)》之銘言: > 我最近在用Johnson M. Hart的書學windows的系統程式設計 > 書上給出了這份使用CreateFile()的程式碼 簡單實作linux上的cp指令 > https://ideone.com/P9q9SD C++ 標準的 main() prototype 為: int main(int argc, char* argv[]) 依這個 prototype,argv 是一個「char*」的陣列。 其中的每一個 char*,都是一個指向「ANSI 字串」的指標。 這個情況下,argv[1] 代表你的第一個參數 ("a.txt")。 記憶體示意圖如下: https://i.imgur.com/SgRzyVL.png 右邊那些文字字元,一格代表一個 byte (8-bit)。 後面 "???" 的意思是:你不能保證後面是什麼。 這可能會引發一些安全性的問題(後面會提到)。 可是你的 main() 宣告變成: int main(int argc, LPTSTR argv[]) 當編譯器的設定為 Unicode 時,LPTSTR 最終會被展開為 wchar_t*。 (註:wchar_t 在 Windows 系統中長度為 16-bit;在 Linux 中則是 32-bit) 所以此時,(編譯器會認為)argv 是一個「wchar_t*」的陣列。 但是,你的記憶體分佈還是跟前面那張圖一樣! 這個時候,編譯器會認為你的 argv[1] 指向一個由「Unicode 字元」組成的字串。 所以,程式在解讀你原本的 char 字串中的每「兩個 8-bit 字元」, 組成 16-bit 資料,當成一個 UTF-16 字元來解譯! 如果用 VC++ 的 debugger 來觀察: https://i.imgur.com/3zvpj0n.png 這就是你傳入 CreateFile() 中的字串。想當然而 "File Not Found"。 而且,除了內容錯誤外,這個字串還有另一個安全性問題: wchar_t 字串的結尾也是 '\0',但長度是 16-bit。 所以 ANSI 的 8-bit '\0' 無法結束字串。 可以參考 debugger 那張圖的範例,argv[0] 其實還沒有結束, 會一直延續到記憶體有 0x0000 的地方為止! 如果處理不當的話,這個字串可能會存取到不該存取到的記憶體,造成安全問題。 ======================================= 你也許會想:為什麼我的 argv 用錯型別,但編譯器還是給我過? 老實說,我也沒有很好的答案。 我只知道 C/C++ 對於 main() 參數的型別檢查,一向非常寬鬆。 那如果我們把 LPTSTR 換回 char* 呢? 我想你也試過了,這樣是不行的。 原因在於你想把 argv[0] 傳入 CreateFile()。 CreateFile() 其實是個巨集,在 Unicode build 下,它會展開為 CreateFileW(), 此時,它的第一個參數為 LPCWSTR,展開後為 const wchar_t*。 你想要把 char* 傳進去,編譯器不會給過的。 ======================================= 那為何選 MBSC 就會過呢? 當你選 MBSC(嚴格說是「非 Unicode」)的時候,LPTSTR 就會展開為 char*, 而 CreateFile() 也會被展開為 CreateFileA()。 此時的第一個參數就是 LPCSTR,展開為 const char*。 這樣就可以過了。執行起來也沒有問題。 但是選 MBSC 有什麼問題? 第一,你沒有辦法處理 Unicode 的檔名。 我其實不太清楚 Windows 內部的原則,但依據我的實驗, 如果你用 char* argv[] 去接參數, 中文的參數會以 Big-5 的編碼傳到程式中,日文則會是 Shift-JIS。 這樣的資料如果不經處理直接傳進 CreateFileA() 會不會正確執行?我不敢保證。 第二,現在的 Windows 核心都是用 Unicode 來處理的。 雖然 Windows 提供你 A 版本的 Win32 API,但其實內部也只是幫你轉成 Unicode, 再去呼叫 W 的版本。效率一定比較差。 Windows 保留 A 版本只是為了向前相容,非必要不建議再使用了。 ======================================= 所以,如果你想處理命令列參數,最好的方法,應該是改用 wmain。 或至少,改用 _tmain,然後編譯選項選 Unicode。 (其實如此一來,_tmain 就會被展開成 wmain 了) 如果你堅持使用 main(而且 argv 型別為 char* []), 那其實,你是還可以用 CreateFileA()....... XDDDD --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 223.140.220.215 (臺灣)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1693391849.A.7F2.html ※ 編輯: closer76 (223.140.220.213 臺灣), 08/30/2023 18:47:19 ※ 編輯: closer76 (223.140.220.213 臺灣), 08/30/2023 19:53:49
1F:推 almostreal: 推 好懂 08/30 22:33
2F:推 sarafciel: 很清楚 推一個 08/31 08:55
3F:推 xavier13540: 我後來改_tmain就編譯成功了 實際上書上後面的範例程 08/31 19:08
4F:→ xavier13540: 式碼也都改用_tmain 可能是10多年前的msvc沒有定義 08/31 19:09
5F:→ xavier13540: UNICODE和_UNICODE兩個macro(? 08/31 19:09
6F:→ closer76: 以前的msvc的確有可能預設不是 UNICODE 模式,不過應該 08/31 19:28
7F:→ closer76: 可以手動更改設定。 08/31 19:28
8F:推 xam: 其實十幾二三十年前的程式書對外行人要入門蠻容易走遠路的 09/01 03:48
9F:→ xam: 以前用的寫法後來可能不相容或被棄用,但新手看不出這些 09/01 03:50
10F:推 v86861062: 推推推 09/01 12:21
11F:推 lwecloud: 至少WIN32 API這十幾年來沒什麼變化(? 09/01 14:53
12F:→ lwecloud: 十年前的XCODE或AS的書現在可能連hello world都印不出來 09/01 14:54
13F:推 ctrlbreak: 查了一下Windows SDK手冊 98年已經建議大家用unicode了 09/01 15:29
14F:→ xam: 我是覺得有時候一開始舊範例就編不過也未必是壞事,早早跳過去 09/01 20:01
15F:→ xam: 找新的資料還不會浪費時間 09/01 20:01
16F:推 lc85301: 太神啦 09/01 20:41
17F:推 cloki: 我新手這部份真的不好懂 09/02 21:02
18F:→ closer76: 用十幾年前的書有時實在是不得已啊!我們公司現在還在用 09/04 11:45
19F:→ closer76: ATL 寫 COM 元件....但講 ATL 最詳細的 ATL Internals 09/04 11:46
20F:→ closer76: 最新版已經是2006年出版的,我好不容易買到一本二手花了 09/04 11:48
21F:→ closer76: 好幾個月才寄到我手上....orz 09/04 11:48
22F:推 ntps60803orz: 推好心人 09/16 10:08







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:iOS站內搜尋

TOP