作者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/m.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