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 --
QR Code



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 223.140.220.215 (台湾)
※ 文章网址: https://webptt.com/cn.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灯, 水草

请输入看板名称,例如:BabyMother站内搜寻

TOP