[問題] VC++ 字元集"Unicode"下使用MySQL

看板C_and_CPP作者 (ChingYue)時間7年前 (2017/06/16 18:05), 7年前編輯推噓12(12050)
留言62則, 3人參與, 最新討論串1/1
開發平台(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://www.ptt.cc/bbs/C_and_CPP/M.1497607559.A.4EA.html

06/17 23:11, , 1F
你應該在unicode用tchar,然後要用char時候只要sprintf
06/17 23:11, 1F

06/17 23:11, , 2F
到char buffer就好了
06/17 23:11, 2F

06/17 23:12, , 3F
如果更菜鳥一點,用multibytetowidebyte也可以
06/17 23:12, 3F

06/17 23:13, , 4F
multibytetowidebyte API應該沒拼錯吧?很久沒寫vc了
06/17 23:13, 4F

06/17 23:14, , 5F
啊應該是widebytetomultibyte啦
06/17 23:14, 5F

06/17 23:15, , 6F
果然老了,windowsAPI記不住了
06/17 23:15, 6F

06/18 00:04, , 7F
良好的習慣用tchar不要用wchar or char
06/18 00:04, 7F

06/18 06:33, , 8F
這裡其實不是 TCHAR/wchar_t/char 的問題
06/18 06:33, 8F

06/18 06:33, , 9F
而是 MySQL API 只收 const char * 的關係
06/18 06:33, 9F

06/18 06:33, , 10F
雖然我沒用過, 但根據我在 PHP 的經驗, 這個 const char *
06/18 06:33, 10F

06/18 06:35, , 11F
字串的編碼應該是先前 set names 所設定的編碼
06/18 06:35, 11F

06/18 06:35, , 12F
那麼當原 PO 手上有的是 wchar_t 時, 就必須要先轉碼成
06/18 06:35, 12F

06/18 06:35, , 13F
對應編碼的 const char * 字串再送進去
06/18 06:35, 13F

06/18 06:36, , 14F
如果是 set names utf8; 的話, 用上面推文講的 windows API
06/18 06:36, 14F

06/18 06:37, , 15F
WideCharToMultiByte() 函數就可以轉了, 詳情可查 MSDN
06/18 06:37, 15F

06/18 06:37, , 16F
這裡反而當使用 TCHAR 會搞亂, 因為如果 TCHAR 是 char 時
06/18 06:37, 16F

06/18 06:39, , 17F
要先把這個 char* 字串轉成 wchar_t* 的 Unicode 字串
06/18 06:39, 17F

06/18 06:39, , 18F
(使用的是上面那個函式的反向版 MultiByteToWideChar() )
06/18 06:39, 18F

06/18 06:40, , 19F
再轉成 UTF-8 字串才能送進去
06/18 06:40, 19F

06/18 06:40, , 20F
比 TCHAR 是 wchar_t 時多了一個步驟
06/18 06:40, 20F

06/18 06:41, , 21F
如果原 PO 沒有想要維護兩個版本的程式那建議不要 TCHAR
06/18 06:41, 21F

06/18 06:41, , 22F
而就直接使用 wchar_t 就行了
06/18 06:41, 22F

06/18 14:10, , 23F
就說在unicode環境只要把tchar sprintf到char buffer就可
06/18 14:10, 23F

06/18 14:10, , 24F
以餵給sql api了,widebytetomultibyte也可以啦,不過這
06/18 14:10, 24F

06/18 14:10, , 25F
種情況用widebytetomultibyte是菜逼巴的人用的
06/18 14:10, 25F

06/18 14:11, , 26F
樓上那個菜逼巴是聽不懂人話喔
06/18 14:11, 26F

06/18 14:26, , 27F
這麼厲害? TCHAR 可以直接 sprintf 到 char buffer ?
06/18 14:26, 27F

06/18 16:16, , 28F
廢話,windows 環境wide string 可以直接sprintf到char b
06/18 16:16, 28F

06/18 16:16, , 29F
uffer,一堆菜逼巴還在用widebytetomultibyte
06/18 16:16, 29F

06/18 16:18, , 30F
不過只限ascii code
06/18 16:18, 30F

06/18 17:12, , 31F
那它還定義 _stprintf 跟 swprintf 幹嘛?
06/18 17:12, 31F

06/18 21:03, , 32F
...要不要來做個實驗? 就印個 "一" 字就好
06/18 21:03, 32F
謝謝兩位前輩 我大概了解問題了 我會再去GOOGLE 嘗試看看! 非常謝謝兩位! ※ 編輯: chingyue (114.45.198.45), 06/19/2017 10:08:02

06/19 10:04, , 33F
......等等我看到了你的但書: 只限 ASCII Code = =
06/19 10:04, 33F

06/19 10:05, , 34F
不過就算這樣還是不行的...除非你的 char buffer 別有用途
06/19 10:05, 34F

06/19 10:07, , 35F
再不然就是你以為是 _UNICODE 其實是 _MBCS
06/19 10:07, 35F

06/19 10:07, , 36F
所以 TCHAR 還是 char, 那自然可以 sprintf 到 char
06/19 10:07, 36F

06/19 10:08, , 37F
這似乎也能解釋為什麼你會有只限 ASCII 的但書在
06/19 10:08, 37F

06/19 12:17, , 38F
樓上的菜逼巴,這只是windows的小技巧之一,另外他的char
06/19 12:17, 38F

06/19 12:17, , 39F
buffer是要餵給sql api的,又不是要處理拉丁字母,阿拉
06/19 12:17, 39F

06/19 12:17, , 40F
伯字母,中文等等,
06/19 12:17, 40F

06/19 12:17, , 41F
另外TCHAR就是widebyte沒錯,只是format不是%s而是%?自己
06/19 12:17, 41F

06/19 12:17, , 42F
Google吧
06/19 12:17, 42F

06/19 12:26, , 43F
看到兩個菜逼巴一直在回文,原po對multibyte或是widebyte
06/19 12:26, 43F

06/19 12:26, , 44F
不熟的話用widebyte <-> multibyte先頂著吧
06/19 12:26, 44F
不好意思 小弟才疏學淺 今天有研究了一下那些編碼轉換 但是還是不太清楚,我等等會再去研究看看 我先嘗試前輩你說的使用TCHAR 要使用char在轉換過去 程式碼:http://codepad.org/yZ7vViUP 但是一樣在要連接MySQL的時候會發生問題 圖:http://i.imgur.com/m9yAgqm.jpg
所以我將要帶入的參數改為char 執行後卻發生存取違規 錯誤圖:http://i.imgur.com/fWtUYBW.jpg
執行時的程式碼:http://codepad.org/61lN5IUN 請問我是有哪邊沒有設定好嗎?

06/19 14:38, , 45F
不好意思, TCHAR 是 Visual Studio 獨有的東西
06/19 14:38, 45F

06/19 14:39, , 46F
就是為了一支程式能藉給定 _UNICODE 或 _MBCS 編出不同版本
06/19 14:39, 46F

06/19 14:40, , 47F
所以不會有 printf 的 %? 語法, 只會有 _stprintf 的 %s
06/19 14:40, 47F

06/19 14:40, , 48F
用 printf 印一個 TCHAR 一定是搞錯了什麼
06/19 14:40, 48F

06/19 14:48, , 49F
然後, sql 敘述並不只會有拉丁字母, 指定欄位名和給值時
06/19 14:48, 49F

06/19 14:48, , 50F
都會需要給定實際字串內容, 這正是 MYSQL_SET_CHARSET_NAME
06/19 14:48, 50F

06/19 14:49, , 51F
的用途; 我不相信一個有一定規模的資料庫會沒有字串資料
06/19 14:49, 51F

06/19 14:50, , 52F
甚至在開一個表格時對字串欄位都需要給定編碼了
06/19 14:50, 52F

06/19 14:50, , 53F
雖然我只能猜測, 但它 API 設計只吃 char* 的理由
06/19 14:50, 53F

06/19 14:50, , 54F
很有可能就是為了相容各種編碼, 因此只能以最原始的 char*
06/19 14:50, 54F

06/19 14:51, , 55F
進行傳送, 再使用所設定的編碼進行解釋 / 填入資料庫
06/19 14:51, 55F

06/19 14:51, , 56F
那為了要給定正確的編碼給這些欄位, 這樣子的轉碼是必須的
06/19 14:51, 56F
小弟嘗試使用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

06/20 23:14, , 57F
_s 的函數需要傳入目標空間的最大大小, 位置在空間後面
06/20 23:14, 57F

06/20 23:15, , 58F
所以你需要 swprintf_s(szDir, MAX_PATH, L"%s%s*", ...)
06/20 23:15, 58F

06/20 23:30, , 59F
關於 wcstombs, 它需要配合 C 語言的 locale 介面來使用
06/20 23:30, 59F

06/20 23:30, , 60F
問題是 setlocale 的設定方式是跟系統相關的
06/20 23:30, 60F

06/20 23:31, , 61F
那這樣倒不如直接使用所在系統的 API 來做轉換
06/20 23:31, 61F

06/20 23:31, , 62F
以你的狀況就是 Windows API
06/20 23:31, 62F
謝謝您 我現在對編碼有比較了解了 正在慢慢修改程式碼 ※ 編輯: chingyue (1.160.7.218), 06/21/2017 15:07:07
文章代碼(AID): #1PGws7Jg (C_and_CPP)