這篇文章主要講解了“C++跨平臺(tái)開(kāi)發(fā)遇到的問(wèn)題有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“C++跨平臺(tái)開(kāi)發(fā)遇到的問(wèn)題有哪些”吧!
創(chuàng)新互聯(lián)建站主要從事網(wǎng)站設(shè)計(jì)、成都網(wǎng)站設(shè)計(jì)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)岑鞏,十載網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):18982081108
在我的開(kāi)發(fā)環(huán)境,clang 編碼默認(rèn)是 utf8, VS 是 GB2312(代碼頁(yè)是 936),它們都兼容 ASCII。
假如代碼文件中只出現(xiàn)英文,兩端都可編譯。假如代碼中出現(xiàn)中文,文件編碼為 utf8, iOS 編譯沒(méi)有問(wèn)題,VS 會(huì)出現(xiàn)編譯錯(cuò)誤 error C2001。假如設(shè)置編碼為 utf16, VS 編譯沒(méi)有問(wèn)題,而 iOS 會(huì)出現(xiàn)編譯錯(cuò)誤 encoding is not supported。因此假如代碼有中文,需要將源文件編碼修改為 Unicode(UTF8 帶簽名)- 代碼頁(yè) 65001。
參見(jiàn) vs編譯 error C2001: 常量中有換行符 中文無(wú)法通過(guò)編譯
另外假如包含中文字符串,直接讀取使用,程序運(yùn)行起來(lái)很容易出現(xiàn)亂碼。類似這樣的代碼:
const char* str = "你好啊,世界";
想將 str 的文字在不同平臺(tái)都顯示正確,是不可控的。跨平臺(tái)代碼不應(yīng)該使用中文,絕對(duì)不能用中文定義字符串再讀取,更嚴(yán)格的甚至不能用中文寫注釋。假如要顯示中文字符串,應(yīng)該將其從程序中分離出來(lái),寫在一個(gè) utf8 編碼的配置文件中,再動(dòng)態(tài)讀取。
我們就碰坑了,我們本意是在導(dǎo)出一個(gè) lua Api 的時(shí)候,自動(dòng)生成對(duì)應(yīng)的文檔。有類似這樣的代碼:
ADD_METHOD_WITH_DOC(Context,nv12ToRGBPass, "獲取顏色空間 nv12 到 rgb 的著色器程序","3.2","[Program](#program)", "program",0)
后來(lái)發(fā)覺(jué)在 Windows 上編譯通過(guò),iOS 編譯不過(guò)。修改編碼后, iOS 編譯過(guò)了,Windows 上又編譯不過(guò)。當(dāng)兩端都編譯過(guò)了,但又亂碼了。最后只好都寫成英文,自動(dòng)生成英文文檔。
在 VS 上,int8_t
實(shí)際上是 char 的 typedef,也就是說(shuō) int8_t
和 char 是同類型的。但是在 iOS 上,int8_t 和 char 是不同類型的。下列代碼
printf("%d\n", (int)std::is_same::value);
在 VS 上輸出 1,在 iOS 上輸出 0。這刷新我認(rèn)知,我一直以為 char 和 int8_t 是相同的。因?yàn)檫@區(qū)別,又踩坑了。
為了方便寫 lua 導(dǎo)出,我們用了 LuaCpp 的庫(kù),里面有這代碼
typedef LOKI_TYPELIST_15(bool, char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, float, double,std::string, luaObject, luatable, int64_t) SupportType;
這里定義了一個(gè) Loki 的 typelist, 包含支持自動(dòng)轉(zhuǎn)換的類型。typelist 參見(jiàn)書籍C++設(shè)計(jì)新思維。
LuaCpp 基本都是模板代碼,假如類型 T 屬于 SupportType,就可執(zhí)行自動(dòng)轉(zhuǎn)換的代碼,不然就需要手寫轉(zhuǎn)換,假如沒(méi)有手寫轉(zhuǎn)換,對(duì)于此類型 T, 就會(huì)直接崩掉。
這里的代碼很老了,一直都運(yùn)行正常。直到某個(gè)接口出現(xiàn)了 int8_t,于是 VS 上運(yùn)行正常,iOS 上崩潰了。
同理,int8_t, uint8_t, int16_t, uint16_t 也需要注意。
類似的模板代碼,最好還是乖乖地使用標(biāo)準(zhǔn)庫(kù)中的 std::is_integral 吧。不要那么聰明自己手寫 typelist 了。
__VA_ARGS__ 可用于不定參數(shù)的宏。但是它的行為在 VS 和 clang 上是有區(qū)別的。如下面代碼
#include#define MY_PRINT(format, ...) printf(format, __VA_ARGS__)int main(int argc, const char* argv[]){MY_PRINT("Hello, World");return 0;}
在 VS 上可以編譯通過(guò)。但在 clang 上確實(shí)編譯失敗,clang 編譯器的 __VA_ARGS__ 不能展開(kāi) 0 個(gè)變長(zhǎng)參數(shù)的。寫成
MY_PRINT("Hello, World, %d", 1);
才可以正確展開(kāi)。為了展開(kāi) 0 個(gè)參數(shù),需要寫成 ##__VA_ARGS__, 定義為
#define MY_PRINT(format, ...) printf(format, ##__VA_ARGS__)
參考 Variadic macros with zero arguments
一個(gè)工程經(jīng)常有多個(gè)動(dòng)態(tài)模塊。在 VS 上,動(dòng)態(tài)模塊為 dll 文件; iOS 上為 framework 或者 dylib。VS 在跨模塊時(shí),默認(rèn)符號(hào)是不導(dǎo)出的。clang 默認(rèn)符號(hào)都是導(dǎo)出的。
在 VS 上,當(dāng)想在 A 模塊中定義某個(gè)類或者某個(gè)函數(shù),讓 B 模塊使用,就需要使用 __declspec(dllexport)
、__declspec(dllimport)
標(biāo)明。通常會(huì)定義一些宏,比如。
#if defined(OF_WIN32) || defined(_WIN32) || defined(WIN32)# ifdef MODULE_A_API_LIB# define MODULE_A_API __declspec(dllexport)# else# define MODULE_A_API __declspec(dllimport)# endif#else# define MODULE_A_API#endif
之后需要跨模塊使用的函數(shù)或者類寫成
class MODULE_A_API TestClass {};MODULE_A_API void myfunction(int a, int b);
通常都沒(méi)有問(wèn)題,假如忘記寫導(dǎo)出,就會(huì)鏈接錯(cuò)誤。但一旦涉及到模板和靜態(tài)變量,這種平臺(tái)的差別,就會(huì)是個(gè)坑。
模板代碼通常會(huì)直接寫在頭文件中,比如下代碼。
// myheader.htemplateclass TemplateClass {public:static std::string str;};template std::string TemplateClass ::str;
在模塊中,包含了頭文件 myheader.h,就可以使用 TemplateClass 了。假如這時(shí)模塊 A 使用語(yǔ)句設(shè)置 str 的值
TemplateClass::str = "Hello, World";
之后模塊 B 讀取 str 的值。
std::string str = TemplateClass::str;
在 VS 中,模塊 A 和模塊 B 雖然都使用 TemplateClass
而在 clang 編譯器中,默認(rèn)是導(dǎo)出的。于是模塊 A 和模塊 B 看到的是相同的 TemplateClass
這種 Bug 比較隱蔽,可以正常編譯,也可以運(yùn)行,但實(shí)際結(jié)果就是不對(duì)。我們就踩過(guò)類似的坑。
前文說(shuō)過(guò),我們使用了 LuaCpp 這個(gè)庫(kù)來(lái)導(dǎo)出 lua。這個(gè)庫(kù)是個(gè)模板庫(kù),它包含一些靜態(tài)變量,用來(lái)實(shí)現(xiàn)自動(dòng)注冊(cè)。我們?cè)谀K A 中注冊(cè)了一批 lua 類。之后在模塊 B 中往 lua 虛擬機(jī)壓注冊(cè)過(guò)的類對(duì)象,在 iOS 上運(yùn)行正常,但在 Windows 上就異常。因?yàn)樵谀K B 中看來(lái),LuaCpp 的記錄中,這些類根本就沒(méi)有被注冊(cè)過(guò)。
感謝各位的閱讀,以上就是“C++跨平臺(tái)開(kāi)發(fā)遇到的問(wèn)題有哪些”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)C++跨平臺(tái)開(kāi)發(fā)遇到的問(wèn)題有哪些這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!