2011年3月19日
#
以下是來自Google Protobuf Documents里的一句話:
As you can see, each field in the message definition has a unique numbered tag. These tags are used to identify your fields in the
message binary format , and should not be changed once your message type is in use. Note that tags with values in the range 1 through 15 take one byte to encode. Tags in the range 16 through 2047 take two bytes. So you should reserve the tags 1 through 15 for very frequently occurring message elements. Remember to leave some room for frequently occurring elements that might be added in the future.
這里要做一個解釋,就是為什么是1到15,以及16到2047呢?
1到15,僅使用1bytes。每個byte包含兩個部分,一個是field_number一個是tag,其中field-number就是protobuf中每個值后等號后的數字(在C++和Java中,如果不設置這個值,則它是隨機的,如果在Python中,不設置,它則不被處理(這個在message binary format 中的Field Order一節中有提到)。那么我們可以認為這個field_number是必須的。那么一個byte用來表達這個值就是0 00000 000 ,其中紅色表示是否有后續字節,如果為0表示沒有也就是這是一個字節,藍色部分表示field-number,綠色部分則是wire_type部分,表示數據類型。也就是(field_number << 3) | wire_type。其中wire_type只有3位,表示數據類型。那么能夠表示field_number的就是5位藍色的數字,5位數字能夠表達的最大范圍就是1-15(其中0是無效的)。 16到2047,與上面的規則其實類似,下面以2bytes為例子,那么就有1 0000000 0 0000 000 ,其中紅色部分依然是符號位,因為每個byte的第一位都用來表示下一byte是否和自己有關,那么對于>1byte的數據,第一位一定是1,因為這里假設是2byte,那么第二個byte的第一位也是紅色,刨除這兩位,再扣掉3個wire_type位,剩下11位(2*8-2-3),能夠表達的數字范圍就是2047(211 )。 參考資料:
http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html http://code.google.com/apis/protocolbuffers/docs/encoding.html
zig-zag:就是把(-1)1000 0001變成0000 0011,注意最后一個1是符號位,也就是2,那么如果是個int32的話,1000 0000 0000 0000 0000 0000 0000 0001 就變成了000 0000 0000 0000 0000 0000 0000 00011,那么也就是11了,那么可以節約很多符號位。
http://goo.gl/2wRKb 用位運算來表示把一個負數轉換成zig-zag編碼,就是
int32是:(n << 1 ) ^ ( n >> 31 )
int64是:
( n << 1 ) ^ ( n >> 63 )
也就是說,如果是負數,對于32位最多能省去30格(其中1格是符號位,另一個代表最小值1,此處假設“正負0”不合法)。同理,64位最多能省去62位。當然比較極端的是所有的位數都被用上了。
2010年9月6日
#
如何當前操作系統是不是64位?如何判斷當前應用程序是否在Wow64下運行?
首先什么是Wow64?很多朋友一看到64就認為這個方法是判斷當前系統是否是64bit的,其實不然。Wow64是Windows-On-Windows64的意思,它是指在64位的操作系統上(不是指64位的CPU)運行32位應用程序的兼容平臺。
下面是MSDN中一段IsWow64的應用程序:
BOOL IsWow64 ()
{
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS ) (HANDLE , PBOOL );
LPFN_ISWOW64PROCESS fnIsWow64Process ;
BOOL bIsWow64 = FALSE ;
fnIsWow64Process = (LPFN_ISWOW64PROCESS )GetProcAddress ( GetModuleHandle (_T ("kernel32" )), "IsWow64Process" );
if (NULL != fnIsWow64Process )
{
fnIsWow64Process (GetCurrentProcess (),&bIsWow64 );
}
return bIsWow64 ;
}
下面的代碼用來檢測這個程序的結果:
if ( IsWow64 () == TRUE )
{
_tprintf (_T ("IsWow64() == TRUE\n" ));
}
else
{
_tprintf (_T ("IsWow64() == FALSE\n" ));
}
讓我們編譯一下這個程序。
我們需要的是64位的操作系統,比如XP64bit,Windows 2008 R2等都是64bit操作系統。
在64位的操作系統上運行的kernel32.dll中,將會實現IsWow64Process方法,而在32位系統中提供的kernel32.dll中則沒有提供相關函數的實現。
比較迷惑人的則是bIsWow64,其實仔細看MSDN中的Remark,會發現:
If the application is a 64-bit application running under 64-bit Windows, the Wow64Process parameter is set to FALSE.也就是說64位應用程序跑在64位的操作系統上,bIsWow64的值將是FALSE而不是TRUE。
因此我們需要分別將我們的程序編譯成Win32平臺和x64平臺的,如果你用Visual Studio進行編譯,默認安裝則只包含32位的編譯器/鏈接器,即便你是在64位操作系統上安裝,也是一樣的。你需要在VC++節點下勾選x64選項才可以,Itanium則需要在Server平臺下安裝才可勾選。然后在編譯的時候,分別選擇Win32和x64進行編譯。
編譯后,運行,結果如我們分析的一樣:
在64位系統上運行Win32編譯配置的結果是IsWow64() == TRUE,而x64編譯配置的結果是IsWow64() == FALSE。
如果想要知道當前系統是否是64位的,則可以通過下面的方法:
BOOL Is64bitSystem ()
{
SYSTEM_INFO si ;
GetNativeSystemInfo (&si );
if (si .wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si .wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
{
return TRUE ;
}
else
{
return FALSE ;
}
}
注意:需要注意是GetNativeSystemInfo 函數從Windows XP 開始才有, 而 IsWow64Process 函數從 Windows XP with SP2 以及 Windows Server 2003 with SP1 開始才有。
2010年9月5日
#
摘要: http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/ 英特爾? 多線程應用開發指南 提交新文章 Published On : 2010年02月25日 20:00 評級 請登錄后評級!當前分數: 0 由 0 用戶 請登錄后評級!當前分數: 0 ...
閱讀全文
2010年9月4日
#
目的:測試MAX_PATH路徑與文件名的關系。
結論:MAX_PATH代表從盤符開始到文件名結尾的C字符串長度(長度+1)的最大長度。也就是假設C:\a.txt共8個字符,長度為9,MAX_PATH通常為260,其中這個文件全名的長度不能大于260。
測試代碼:
#include "stdafx.h"
#include <atlbase.h>
#include <windows.h>
#include <atlfile.h>
#include <atlstr.h>
#include <iostream>
#include <string>
BOOL IsFileExist ( LPCTSTR lpszFileName )
{
DWORD dwAttr = ::GetFileAttributes ( lpszFileName );
if ( dwAttr == 0xFFFFFFFF )
{
return FALSE ;
}
if ( ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) > 0 )
{
return FALSE ;
}
return TRUE ;
}
BOOL DeleteFiles ( LPCTSTR lpszPath )
{
TCHAR szFrom [_MAX_PATH +1] = {_T ( '\0' )};
lstrcpy ( szFrom , lpszPath );
SHFILEOPSTRUCT shf ;
memset ( &shf , 0, sizeof ( SHFILEOPSTRUCT ) );
shf .hwnd = NULL ;
shf .pFrom = szFrom ;
shf .wFunc = FO_DELETE ;
shf .fFlags = FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION |
FOF_NOERRORUI | FOF_SILENT ;
return SHFileOperation ( &shf ) == 0;
}
BOOL WriteBinaryBytesToFile ( LPCTSTR fileName , unsigned char * data ,
unsigned int datasize , BOOL bAppend )
{
CAtlFile file ;
if ( !bAppend && IsFileExist ( fileName ))
DeleteFiles ( fileName );
HRESULT ret = file .Create ( fileName , FILE_WRITE_DATA , FILE_SHARE_WRITE , bAppend ?OPEN_ALWAYS :CREATE_ALWAYS );
if ( !SUCCEEDED ( ret ) )
return FALSE ;
if ( bAppend )
{
file .Seek ( 0, FILE_END );
}
unsigned char *pos = data ;
while ( datasize > 0 )
{
DWORD dwWrite = 0;
if ( file .Write ( pos , datasize , &dwWrite ) != S_OK )
{
file .Close ();
return FALSE ;
}
datasize -= dwWrite ;
pos += dwWrite ;
}
file .Close ();
return TRUE ;
}
BOOL GCreateFile (std ::string & fileNamePath ,
std ::string & fileNameExt ,
int shortNameLength ,
std ::string & data )
{
char c [] = "a" ;
std ::string fileName ;
fileName .append (fileNamePath );
while ( shortNameLength -- )
{
fileName .append (c );
++*c ;
if ( *c > 'z' )
{
*c = 'a' ;
}
}
fileName .append (fileNameExt );
std ::cout << "fileName:" << fileName << std ::endl ;
std ::cout << "fileName.size():" << fileName .size () << std ::endl ;
std ::cout << "MAX_PATH" << MAX_PATH << std ::endl ;
if ( WriteBinaryBytesToFile (fileName .c_str (), (unsigned char *)data .data (), data .size (), FALSE ) )
{
std ::cout << "++++++++++++++WriteBinaryBytesToFile successful.++++++++++++++" << std ::endl ;
return TRUE ;
}
else
{
std ::cout << "==============WriteBinaryBytesToFile error==============." << std ::endl ;
return FALSE ;
}
}
int _tmain (int argc , _TCHAR * argv [])
{
std ::string fileNamePath = "E:\\MyCPlusProject\\TestFileNameMaxLength\\TestFileNameMaxLength\\Output\\" ;
std ::string fileNameExt = ".txt" ;
std ::string data ("This is a content." );
int shortNameLength ;
shortNameLength = MAX_PATH - fileNameExt .size () - fileNamePath .size ();
GCreateFile (fileNamePath , fileNameExt , shortNameLength , data );
std ::cout << "------------------" << std ::endl ;
shortNameLength = MAX_PATH - fileNameExt .size () - fileNamePath .size () - 1;
GCreateFile (fileNamePath , fileNameExt , shortNameLength , data );
return 0;
}
提示:右鍵項目屬性,將字符集設置為“未設置”。
最近遇到一個跟Windows(不是指操作系統,而是一個::CreateWindow的結果)有關的問題。
情況是這樣的,通常的應用程序內的事件傳遞一般場景都是類似在窗體A上點擊按鈕1,彈出一個窗體B。面對這樣的場景只要::SetWindowActive(HWND wnd)即可,這里其實有個隱含的前提,就是wnd的父窗口是出于TOP的狀態,也就是它的父窗口是置頂的,也就是我們能夠在界面上看到它,否則你的其他置頂窗口將依舊置頂。
下面的代碼示意了如何將窗口置頂,因為也沒有對各個方法做深入分析,所以就不多發表言論了:
/*場景:
目標:將子窗口放到置頂(且是HWND_TOP)模式
說明:hMainWnd是主窗口,m_pMMessageWnd->m_hWnd是子窗口
*/
/*1、將窗口從后臺直接提到最前方,需要先將主窗口移上來。*/
HWND hMainWnd = CFramework ::GetInstance ()->GetMainWnd ();
if ( hMainWnd != NULL )
{
SetForegroundWindow (hMainWnd );
BringWindowToTop (hMainWnd );
SetActiveWindow (hMainWnd );
SetWindowPos ( hMainWnd , HWND_TOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
}
/*2、將子窗口置頂*/
if ( m_pMMessageWnd != NULL ) /* true */
{
SetForegroundWindow (m_pMMessageWnd ->m_hWnd );
BringWindowToTop (m_pMMessageWnd ->m_hWnd );
SetActiveWindow (m_pMMessageWnd ->m_hWnd );
SetWindowPos ( m_pMMessageWnd ->m_hWnd , HWND_TOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
SetWindowPos ( m_pMMessageWnd ->m_hWnd , HWND_NOTOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
}
/*3、放在后面的原因是避免子窗口還未彈出,點擊窗體外的時候被放到后面去,所以等窗口出來后再取消置頂*/
if ( hMainWnd != NULL )
{
SetWindowPos ( hMainWnd , HWND_NOTOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
}
/*4、避免被主窗口給壓了*/
if ( m_pMMessageWnd != NULL ) /* true */
{
SetWindowPos ( m_pMMessageWnd ->m_hWnd , HWND_TOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
SetWindowPos ( m_pMMessageWnd ->m_hWnd , HWND_NOTOPMOST , 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE |SWP_SHOWWINDOW );
}
2010年8月28日
#
轉載自:http://developer.51cto.com/art/200702/39608.htm
動態連接庫的創建步驟:
一、創建Non-MFC DLL動態鏈接庫
1、打開File —> New —> Project選項,選擇Win32 Dynamic-Link Library —>sample project —>工程名:DllDemo
2、新建一個.h文件DllDemo.h
#ifdef DllDemo_EXPORTS #define DllAPI __declspec(dllexport) #else #define DllAPI __declspec(dllimport) extern "C" //原樣編譯 { DllAPI int __stdcall Max(int a,int b); //__stdcall使非C/C++語言內能夠調用API } #endif
3、在DllDemo.cpp文件中導入DllDemo.h文件,并實現Max(int,int)函數
#include "DllDemo.h" DllAPI int __stdcall Max(int a,int b) { if(a==b) return NULL; else if(a>b) return a; else return b; }
4、編譯程序生成動態連接庫
二、用.def文件創建動態連接庫DllDemo.dll
1、刪除DllDemo工程中的DllDemo.h文件。
2、在DllDemo.cpp文件頭,刪除 #include DllDemo.h語句。
3、向該工程中加入一個文本文件,命名為DllDemo.def并寫入如下語句:
LIBRARY MyDll
EXPORTS
Max@1
4、編譯程序生成動態連接庫。
動態鏈接的調用步驟:
一、隱式調用
1、建立DllCnslTest工程
2、將文件DllDemo.dll、DllDemo.lib拷貝到DllCnslTest工程所在的目錄
3、在DllCnslTest.h中添加如下語句:
#define DllAPI __declspec(dllimport) #pragma comment(lib,"DllDemo.lib") //在編輯器link時,鏈接到DllDemo.lib文件 extern "C" { DllAPI int __stdcall Max(int a,int b); }
4、在DllCnslTest.cpp文件中添加如下語句:
#include "DllCnslTest.h"http://或者 #include "DllDemo.h" void main() { int value; value = Max(2,9); printf("The Max value is %d\n",value); }
5、編譯并生成應用程序DllCnslTest.exe
二、顯式調用
1、建立DllWinTest工程。
2、將文件DllDemo.dll拷貝到DllWinTest工程所在的目錄或Windows系統目錄下。
3、用vc/bin下的Dumpbin.exe的小程序,查看DLL文件(DllDemo.dll)中的函數結構。
4、使用類型定義關鍵字typedef,定義指向和DLL中相同的函數原型指針。
例:
typedef int(*lpMax)(int a,int b); //此語句可以放在.h文件中
5、通過LoadLibray()將DLL加載到當前的應用程序中并返回當前DLL文件的句柄。
例:
HINSTANCE hDll; //聲明一個Dll實例文件句柄 hDll = LoadLibrary("DllDemo.dll");//導入DllDemo.dll動態連接庫
6、通過GetProcAddress()函數獲取導入到應用程序中的函數指針。
例:
lpMax Max; Max = (lpMax)GetProcAddress(hDLL,"Max"); int value; value = Max(2,9); printf("The Max value is %d",value);
7、函數調用完畢后,使用FreeLibrary()卸載DLL文件。
FreeLibrary(hDll);
8、編譯并生成應用程序DllWinTest.exe
注:顯式鏈接應用程序編譯時不需要使用相應的Lib文件。
下載(Visual Studio 2008驗證通過 ):http://www.shnenglu.com/Files/mymsdn/DllCnsTest.7z
2010年8月11日
#
禁止類成員復制,其核心就在于不允許類外部看見復制函數,包括“拷貝構造函數”、“operator =重載”。
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \private : \ TypeName(const TypeName&); \ TypeName& operator =(const TypeName&)
禁止隱式構造,則可以將默認構造函數隱藏起來,在大多數編譯器中也可以對構造函數增加explicit關鍵字來避免隱式構造。
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \private : \ TypeName(); \ DISALLOW_COPY_AND_ASSIGN(TypeName)
更多解釋詳見《More Effective C++》
2010年7月22日
#
__declspec 關鍵字
// keyword__declspec.cpp : 定義控制臺應用程序的入口點。
//
// ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/kernel_d/hh/Kernel_d/64bitAMD_6db3322a-fe6d-4287-9eda-a9c1378e715d.xml.htm
// The sizeof value for any structure is the offset of the final member,
// plus that member's size, rounded up to the nearest multiple of the largest
// member alignment value or the whole structure alignment value,
// whichever is greater.
#include "stdafx.h"
__declspec ( align ( 32) ) struct Struct__declspec_1
{
int a ;
int b ;
};
__declspec ( align ( 32) ) struct Struct__declspec_2
{
__declspec ( align ( 64) ) int a ;
int b ;
};
__declspec ( align ( 8 ) ) struct Struct__declspec_3
{
int a ; //4 bytes
int b ; //4 bytes
int c ; //4 bytes
};
__declspec ( align ( 8 ) ) struct Struct__declspec_4
{
int a ; //4 bytes
int b ; //4 bytes
};
struct StructNormal
{
int a ; //4 bytes
int b ; //4 bytes
int c ; //4 bytes
};
int _tmain (int argc , _TCHAR * argv [])
{
printf ( "sizeof Struct__declspec_1 is %d.\n" , sizeof ( Struct__declspec_1 )); //32
printf ( "sizeof Struct__declspec_2 is %d.\n" , sizeof ( Struct__declspec_2 )); //64
printf ( "sizeof Struct__declspec_3 is %d.\n" , sizeof ( Struct__declspec_3 )); //16
printf ( "sizeof Struct__declspec_4 is %d.\n" , sizeof ( Struct__declspec_4 )); //8
printf ( "sizeof StructNormal is %d.\n" , sizeof ( StructNormal )); //12
return 0;
}
2010年7月6日
#
摘要: 和大多數內存管理的初衷一致,希望能夠控制內存分配和回收,減少內存碎片,且通常這樣的內存都會預開一段連續內存空間,然后我們自己來管理這段內存。當然通常這樣的需求都很合理,但是實現起來則通常不能完美,比如:效率、算法的選擇、如何減少內存碎片、跟蹤管理內存分配、性能檢測、對系統內存使用的統計、垃圾回收等。下面是我近期實現的一個非常簡陋的程序,甚至可能連基本的要求都無法達到,大家幫忙看看,它究竟有多少缺點...
閱讀全文