std::string 轉換成 char*

** 這篇的程式沒有實際編譯執行過,不保證沒有錯誤 **

很多時候我們得在 C++ 使用 C 語言寫的函式庫,
這時候 std::string 有幾種不同的方法來轉為 char*:

最安全也最常見的用法,是呼叫 std::string.c_str()。
這個函式會回傳一個標準的 char array,但是是唯讀的。

如果我們要讓 char array 可以寫入呢?
那就要先將字串複製到可寫入的 buffer:

變得麻煩了,對吧?

有沒有什麼方法可以直接更新到 string 而不用複製來複製去的呢?
std::string.data() 可以用來做這件事。
它回傳的是 string 內部用來儲存字串的記憶體區塊,所以修改值的話就會反應到 string 去。
不過舊的 C++ 標準並沒有強迫內部的記憶體區塊是連續的,所以這是有一點風險的。
另外,內部的記憶體也不保證會有 NULL 結尾,使用時一定要搭配長度的限制。

但風險也沒有那麼大,Herb Sutter 指出他目前所知的 std::string 實作,都是連續且 NULL 結尾的[1]。
所以用起來還算可以放心。

另外還有一個方式,就是使用陣列運算子。
因為 std::string[] 會回傳單一字元的參考,若對此參考取指標,就可以得到一個能用來修改內容的指標。
然而若對空字串取第一個字元 (empty_string[0]) 的話,不保證能夠得到 ‘\0’。
因此還是建議使用 std::string.data()。

在參考資料[2]裡面有很詳細的解說。基本上 C++11 解決了很多這類不確定的混亂情況,若是允許的話還是用新的標準編譯吧。

參考資料:
[1] http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/
[2] http://stackoverflow.com/questions/347949/how-to-convert-a-stdstring-to-const-char-or-char

GDBM 讀取資料失敗

GDBM 就是 GNU dbm,是一個輕量的 key/value 資料庫。
今天在使用時,發生了開啟檔案失敗的情況,錯誤訊息:File seek error
原因是 GDBM 它在 32bit 與 64bit 的環境下,產生的檔案格式不相容。
也沒什麼好的解決辦法,只能將資料都倒出來再用對應的版本建立資料庫。
若要在 64bit 的環境下編譯成 32bit 來執行,可使用 gcc -m32 來指定編譯 32bit 版本。

C語言網路相關的標頭檔

從網路上找資訊, 最怕的就是找到舊的或錯誤的東西
今兒個找了個範例, 結果遇到無法編譯的問題, 就是因為用的是舊方法

問題主要出在 #include <linux/ip.h> 然後就跳出一堆錯誤:

拿這些訊息去 google 還查不出什麼來, 都是些老舊的文章
後來跑去翻自己以前寫的程式來比對, 才找到真正問題

原因是 linux/ 底下的東西本身是給 kernel 內部使用的
因此開發一般 userland 的程式不應該使用這些
較新的 linux 版本甚至把這些標頭檔也拿掉了

比較正確的作法, 是採用 netinet/ 底下的標頭檔
這是由 POSIX 所規範的標頭檔, 所以用這個開發出來也比較具有移植性
改成使用 netinet/ip.h 以後, 上面遇到的錯誤也就消失了

Ubuntu GCC Link Library 的順序問題

今天在 ubuntu 中了招,Makefile 中這樣寫:

結果一直顯示錯誤:

檢查了 libssl-dev 有安裝,也跑去 /usr/lib 建立一些 link,但是問題都沒有解決。

最後原因是這個:

The –as-needed option also makes the linker sensitive to the ordering of libraries on the command-line. You may need to move some libraries later in the command-line, so they come after other libraries or files that require symbols from them.

Ubuntu 自 11.04 後,預設會將 –as-needed 選項打開,所以參數的順序突然變得很重要了,改成這樣就可以了:

參考資料:
https://wiki.ubuntu.com/NattyNarwhal/ToolchainTransition

使用 fstat() 判斷 File Descriptor 的種類

Beej’s Guide 看到這一句話:select() only works with socket descriptors, not file descriptors (like 0 for stdin),想到我之前曾經把 tun/tap 的 file descriptor 丟進 select 裡面,不曉得我是不是做錯了。於是開始了一連串的搜尋,想要搞清楚 select 到底可以接受哪些 file descriptor…

大約花了快兩天的時間,我把相關的關鍵字都搜尋了一遍,然後把 man 2 select 與 man 2 select_tut 也看完了,接著跑去找出之前的程式,確認 tun/tap 並不是 socket descriptor 但是程式卻正常運作….

最後翻出手邊的 Linux 系統程式設計 這本書,把第二章重新看了一遍,發現書中直接就拿 STDIN_FILENO 丟進 select 來當範例。

嗯…難道是 Beej 亂寫嗎?
跑回去看那一篇文章,才發現他寫的是 Note for Windows Programmers 也就是說其實指的是 Winsock 的情況。

算了,反正看了那堆東西我還是有點收穫的,其中之一就是這個,如何判斷 fd 的種類:

參考:http://pubs.opengroup.org/onlinepubs/009695399/functions/fstat.html

Win32 安裝 openssl 及 vc6 設定

網路上找得到一些編譯成DLL的, 但這邊要做的是static library, 也就是將openssl包進exe中不依賴DLL

1. 安裝ActivePerl

http://www.activestate.com/activeperl/downloads

2. 下載OpenSSL
http://www.openssl.org/source/

3. 將OpenSSL解壓縮到C:\
我這邊使用的是1.0.1c, 所以路徑是C:\openssl-1.0.1c

4. 打開cmd.exe, 執行 perl Configure, prefix是openssl要安裝的目錄, 並不是指下載來的source
cd c:\openssl-1.0.1c
perl Configure VC-WIN32 no-asm –prefix=c:/openssl/
ms\do_ms

5. 這時openssl已經準備好編譯了, 接續上面的cmd, 執行指令
nmake -f ms\nt.mak

6. 若過程順利, 沒有出現錯誤訊息, 即可進行安裝
nmake -f ms\nt.mak install

7. 設定vc6:
Tools -> Options -> Directories -> Show directories for: Include files
add: C:\openssl\include

Tools -> Options -> Directories -> Show directories for: Library files
add: C:\openssl\lib

** 錯誤:
a. 找不到 in6_addr?
編輯 C:\openssl-1.0.1c\apps\s_cb.c 並加入以下程式:
struct in6_addr {
union {
u_char Byte[16];
u_short Word[8];
} u;
};

b. 找不到nmake?
在cmd執行:
“c:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT”