我来解释为什么吧. 这里由Firaxis程序员的愚蠢造成的.
先观察CvInitCore::getLeaderName- const CvWString & CvInitCore::getLeaderName(PlayerTypes eID, uint uiForm) const
- {
- FASSERT_BOUNDS(0, MAX_PLAYERS, eID, "CvInitCore::getLeaderName");
- if ( checkBounds(eID, 0, MAX_PLAYERS) )
- {
- #ifdef CYBERFRONT // text: leader name
- m_szTemp = gDLL->getObjectText(m_aszLeaderName[eID], uiForm, true);
- #else
- m_szTemp = gDLL->getObjectText(CvString(m_aszLeaderName[eID]).GetCString(), uiForm, true);
- #endif // CYBERFRONT
- }
- else
- {
- m_szTemp = "";
- }
- return m_szTemp;
- }
复制代码 Firaxis和Cyberfront的区别在于
Firaxis是- m_szTemp = gDLL->getObjectText(CvString(m_aszLeaderName[eID]).GetCString(), uiForm, true);
复制代码 Cyberfront是- m_szTemp = gDLL->getObjectText(m_aszLeaderName[eID], uiForm, true);
复制代码 让我们先看看m_aszLeaderName和getObjectText的声明, 在英文版和日文版中它们是相同的. 都是:- virtual CvWString getObjectText(CvWString szIDTag, uint uiForm, bool bNoSubs = false) = 0;
复制代码- CvWString* m_aszLeaderName;
复制代码 getObjectText的第一个参数的类型是CvWString, 那么Firaxis的那行代码实际上是- m_szTemp = gDLL->getObjectText(CvWString(CvString(m_aszLeaderName[eID]).GetCString()), uiForm, true);
复制代码 关键之处是- CvWString(CvString(m_aszLeaderName[eID]).GetCString())
复制代码 我先把CvString和CvWString的相关代码摘出- class CvWString : public std::wstring
- {
- public:
- ......
- CvWString(const char* s) { Copy(s); }
- ......
- void Copy(const char* s)
- {
- if (s)
- {
- int iLen = strlen(s);
- if (iLen)
- {
- wchar *w = new wchar[iLen+1];
- swprintf(w, L"%S", s); // convert
- assign(w);
- delete [] w;
- }
- }
- }
- ......
- };
复制代码- class CvString : public std::string
- {
- public:
- ......
- explicit CvString(const std::wstring& s) { Copy(s.c_str()); } // don't want accidental conversions down to narrow strings
- ......
- void Copy(const wchar* w)
- {
- if (w)
- {
- int iLen = wcslen(w);
- if (iLen)
- {
- char *s = new char[iLen+1];
- sprintf(s, "%S", w); // convert
- assign(s);
- delete [] s;
- }
- }
- }
- ......
- const char* GetCString() const { return c_str(); } // convert
- ......
- };
复制代码 由此我们可以得出结论: Firaxis从一个CvWString开始, 经过一系列的类型转换, 最后得到的还是一个CvWString.
Firaxis的愚蠢在于他仅仅是想进行类型转换, 而不是想做什么其它工作. 所以像Cyberfront那样, 直接使用m_aszLeaderName[eID]作为getObject这个函数的第一个参数就行了.
这还没完, 如果仅仅是无用功那还好, 悲剧在于Firaxis的这段代码仅能对latin-1编码的字符串给出正确的转换结果.
关键在于Firaxis使用swprintf(w, L"%S", s)来转换wchar_t和char, 即使不说是错误的, 也是有隐患的.
Cyberfront使用的则是WideCharToMultiByte, 毕竟是欧美以外的公司, 有i18n经验. |