作者chingyue (ChingYue)
看板C_and_CPP
标题[问题] VC++ 字元集"Unicode"下使用MySQL
时间Fri Jun 16 18:05:55 2017
开发平台(Platform): (Ex: Win10, Linux, ...)
win7(win10)
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
VC++(2013)
额外使用到的函数库(Library Used): (Ex: OpenGL, ...)
MySQL API
问题(Question):
各位前辈大家好
之前小弟写了一支程式
使用的字元集为"多位元组"
程式码
http://codepad.org/aUdBuWV3
今天我想把字元集改为"Unicode"
结果发生了错误
无法将引数char转换为'LPCWSTR'
我Google後发现
LPCWSTR = const wchar_t *
所以做了几点修正
1:char改为wchar_t,双引号前面加L
2:sprintf_s改为swprintf_s
3:strlen()改为wcslen()
4:增加 mysql_options(&myCont, MYSQL_SET_CHARSET_NAME, "utf8");
mysql_set_character_set(&myCont, "utf8");
修改後程式码:
http://codepad.org/IhFEG7RM
但是在使用mysql_real_connect()时发生了错误
函式说明:
http://i.imgur.com/GY72hjm.jpg
错误图:
http://i.imgur.com/LWLkqD1.jpg
请问这样是不是要修改标头档?
(有稍微修改一下 结果问题好像越来越大洞...)
还是有其他方法能在Unicode下使用MySQL API ?
恳请各位前辈赐教
谢谢!
程式码(Code):(请善用置底文网页, 记得排版)
多位元组:
http://codepad.org/aUdBuWV3
Unicode :
http://codepad.org/IhFEG7RM
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 122.116.59.114
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1497607559.A.4EA.html
1F:推 pttuser: 你应该在unicode用tchar,然後要用char时候只要sprintf 06/17 23:11
2F:→ pttuser: 到char buffer就好了 06/17 23:11
3F:推 pttuser: 如果更菜鸟一点,用multibytetowidebyte也可以 06/17 23:12
4F:→ pttuser: multibytetowidebyte API应该没拼错吧?很久没写vc了 06/17 23:13
5F:→ pttuser: 啊应该是widebytetomultibyte啦 06/17 23:14
6F:→ pttuser: 果然老了,windowsAPI记不住了 06/17 23:15
7F:推 pttuser: 良好的习惯用tchar不要用wchar or char 06/18 00:04
8F:推 LPH66: 这里其实不是 TCHAR/wchar_t/char 的问题 06/18 06:33
9F:→ LPH66: 而是 MySQL API 只收 const char * 的关系 06/18 06:33
10F:→ LPH66: 虽然我没用过, 但根据我在 PHP 的经验, 这个 const char * 06/18 06:33
11F:→ LPH66: 字串的编码应该是先前 set names 所设定的编码 06/18 06:35
12F:→ LPH66: 那麽当原 PO 手上有的是 wchar_t 时, 就必须要先转码成 06/18 06:35
13F:→ LPH66: 对应编码的 const char * 字串再送进去 06/18 06:35
14F:→ LPH66: 如果是 set names utf8; 的话, 用上面推文讲的 windows API 06/18 06:36
15F:→ LPH66: WideCharToMultiByte() 函数就可以转了, 详情可查 MSDN 06/18 06:37
16F:→ LPH66: 这里反而当使用 TCHAR 会搞乱, 因为如果 TCHAR 是 char 时 06/18 06:37
17F:→ LPH66: 要先把这个 char* 字串转成 wchar_t* 的 Unicode 字串 06/18 06:39
18F:→ LPH66: (使用的是上面那个函式的反向版 MultiByteToWideChar() ) 06/18 06:39
19F:→ LPH66: 再转成 UTF-8 字串才能送进去 06/18 06:40
20F:→ LPH66: 比 TCHAR 是 wchar_t 时多了一个步骤 06/18 06:40
21F:→ LPH66: 如果原 PO 没有想要维护两个版本的程式那建议不要 TCHAR 06/18 06:41
22F:→ LPH66: 而就直接使用 wchar_t 就行了 06/18 06:41
23F:推 pttuser: 就说在unicode环境只要把tchar sprintf到char buffer就可 06/18 14:10
24F:→ pttuser: 以喂给sql api了,widebytetomultibyte也可以啦,不过这 06/18 14:10
25F:→ pttuser: 种情况用widebytetomultibyte是菜逼巴的人用的 06/18 14:10
26F:→ pttuser: 楼上那个菜逼巴是听不懂人话喔 06/18 14:11
27F:→ firose: 这麽厉害? TCHAR 可以直接 sprintf 到 char buffer ? 06/18 14:26
28F:推 pttuser: 废话,windows 环境wide string 可以直接sprintf到char b 06/18 16:16
29F:→ pttuser: uffer,一堆菜逼巴还在用widebytetomultibyte 06/18 16:16
30F:推 pttuser: 不过只限ascii code 06/18 16:18
31F:→ firose: 那它还定义 _stprintf 跟 swprintf 干嘛? 06/18 17:12
32F:推 LPH66: ...要不要来做个实验? 就印个 "一" 字就好 06/18 21:03
谢谢两位前辈
我大概了解问题了
我会再去GOOGLE 尝试看看!
非常谢谢两位!
※ 编辑: chingyue (114.45.198.45), 06/19/2017 10:08:02
33F:→ LPH66: ......等等我看到了你的但书: 只限 ASCII Code = = 06/19 10:04
34F:→ LPH66: 不过就算这样还是不行的...除非你的 char buffer 别有用途 06/19 10:05
35F:→ LPH66: 再不然就是你以为是 _UNICODE 其实是 _MBCS 06/19 10:07
36F:→ LPH66: 所以 TCHAR 还是 char, 那自然可以 sprintf 到 char 06/19 10:07
37F:→ LPH66: 这似乎也能解释为什麽你会有只限 ASCII 的但书在 06/19 10:08
38F:推 pttuser: 楼上的菜逼巴,这只是windows的小技巧之一,另外他的char 06/19 12:17
39F:→ pttuser: buffer是要喂给sql api的,又不是要处理拉丁字母,阿拉 06/19 12:17
40F:→ pttuser: 伯字母,中文等等, 06/19 12:17
41F:→ pttuser: 另外TCHAR就是widebyte没错,只是format不是%s而是%?自己 06/19 12:17
42F:→ pttuser: Google吧 06/19 12:17
43F:推 pttuser: 看到两个菜逼巴一直在回文,原po对multibyte或是widebyte 06/19 12:26
44F:→ pttuser: 不熟的话用widebyte <-> multibyte先顶着吧 06/19 12:26
不好意思
小弟才疏学浅
今天有研究了一下那些编码转换
但是还是不太清楚,我等等会再去研究看看
我先尝试前辈你说的使用TCHAR
要使用char在转换过去
程式码:
http://codepad.org/yZ7vViUP
但是一样在要连接MySQL的时候会发生问题
图:
http://i.imgur.com/m9yAgqm.jpg
所以我将要带入的参数改为char
执行後却发生存取违规
错误图:
http://i.imgur.com/fWtUYBW.jpg
执行时的程式码:
http://codepad.org/61lN5IUN
请问我是有哪边没有设定好吗?
45F:推 LPH66: 不好意思, TCHAR 是 Visual Studio 独有的东西 06/19 14:38
46F:→ LPH66: 就是为了一支程式能藉给定 _UNICODE 或 _MBCS 编出不同版本 06/19 14:39
47F:→ LPH66: 所以不会有 printf 的 %? 语法, 只会有 _stprintf 的 %s 06/19 14:40
48F:→ LPH66: 用 printf 印一个 TCHAR 一定是搞错了什麽 06/19 14:40
49F:→ LPH66: 然後, sql 叙述并不只会有拉丁字母, 指定栏位名和给值时 06/19 14:48
50F:→ LPH66: 都会需要给定实际字串内容, 这正是 MYSQL_SET_CHARSET_NAME 06/19 14:48
51F:→ LPH66: 的用途; 我不相信一个有一定规模的资料库会没有字串资料 06/19 14:49
52F:→ LPH66: 甚至在开一个表格时对字串栏位都需要给定编码了 06/19 14:50
53F:→ LPH66: 虽然我只能猜测, 但它 API 设计只吃 char* 的理由 06/19 14:50
54F:→ LPH66: 很有可能就是为了相容各种编码, 因此只能以最原始的 char* 06/19 14:50
55F:→ LPH66: 进行传送, 再使用所设定的编码进行解释 / 填入资料库 06/19 14:51
56F:→ LPH66: 那为了要给定正确的编码给这些栏位, 这样子的转码是必须的 06/19 14:51
小弟尝试使用wchat_t,并在需要时转成char
因为WideCharToMultiByte比较复杂,我可能要在研究一下才会使用
所以小弟先使用wcstombs来做转换
执行时却会出现 存取违规
错误图:
http://i.imgur.com/AFg9Mbs.jpg
执行程式码:
http://codepad.org/SE7aEBqz
请问我是转换的位子不对,或者一开始变数就设定有错误吗?
※ 编辑: chingyue (114.45.198.45), 06/19/2017 16:45:48
57F:推 LPH66: _s 的函数需要传入目标空间的最大大小, 位置在空间後面 06/20 23:14
58F:→ LPH66: 所以你需要 swprintf_s(szDir, MAX_PATH, L"%s%s*", ...) 06/20 23:15
59F:→ LPH66: 关於 wcstombs, 它需要配合 C 语言的 locale 介面来使用 06/20 23:30
60F:→ LPH66: 问题是 setlocale 的设定方式是跟系统相关的 06/20 23:30
61F:→ LPH66: 那这样倒不如直接使用所在系统的 API 来做转换 06/20 23:31
62F:→ LPH66: 以你的状况就是 Windows API 06/20 23:31
谢谢您
我现在对编码有比较了解了
正在慢慢修改程式码
※ 编辑: chingyue (1.160.7.218), 06/21/2017 15:07:07