A. 如何編譯64位dll程序,有幾種情況,在32位XP上用VC++6.0或者VS2010該怎麼編譯64位的dll。
在64位的操作系統上用vs軟體編譯的dll默認就是64位。
在32位XP上用VC++6.0編譯64位的dll,需要安裝sdk(最新版本是sdk2003),在開始菜單——sdk——open build environment window——windows server 2003 64-bit build environment——set win svr 2003 x64 build env進入命令行,從命令行調用msdev,將vc選項里的include和lib的第一個默認路徑設為sdk目錄下64位頭文件和庫的路徑,編譯出的dll似乎就是64位的了。這個是從網頁上看到的,沒實踐過。
在32位XP上使用vs2010就簡單多了,新建一個項目(解決方案),加入代碼,設置X64,編譯生成即可。
B. 如何在各個版本的VC及64位下使用CPUID指令
一、推薦使用__cpuid、__cpuidex等Intrinsics函數
在32位模式下,我們可以使用內嵌匯編來調用cpuid指令。但在64位模式下,VC編譯器不支持內嵌匯編。
於是微軟提供了Intrinsics函數——編譯器會將Intrinsics函數編譯為對應的機器指令,而且同時支持32位和64位。
例如CPUID指令的對應Intrinsics函數是——
[cpp] view plain
// http://msdn.microsoft.com/en-us/library/hskdteyh.aspx
void __cpuid(
int CPUInfo[4],
int InfoType
);
void __cpuidex(
int CPUInfo[4],
int InfoType,
int ECXValue
);
__cpuidex函數的InfoType參數是CPUID指令的eax參數,即功能ID。ECXValue參數是CPUID指令的ecx參數,即子功能ID。CPUInfo參數用於接收輸出的eax, ebx, ecx, edx這四個寄存器。
早期的CPUID功能只需要一個功能ID參數(eax),這時可以使用__cpuid函數。
後來CPUID的功能越來越強大,一個功能ID參數(eax)參數不夠用,於是加了一個子功能ID(ecx)參數,這時應該採用__cpuidex。
二、用條件編譯判斷VC編譯器對Intrinsics函數的支持性(_MSC_VER)
在__cpuid、__cpuidex等Intrinsics函數時,會遇到以下問題——
1.低版本的VC編譯器沒有intrin.h頭文件。【注】:只有VC2005(或更高)才擁有intrin.h,支持__cpuid。
2.低版本的VC編譯器不支持__cpuidex。【注】:只有VC2008的部分版本及VS2010(或更高)的intrin.h中才有__cpuidex。
這時可以使用條件編譯來判斷VC編譯器的版本。
_MSC_VER是微軟C/C++編譯器——cl.exe編譯代碼時預定義的一個宏,它的值表示cl的版本,它的類型是「int」。例如——
#if _MSC_VER >=1200 // VC++6.0以上
#if _MSC_VER >=1300 // VC2003以上
#if _MSC_VER >=1400 // VC2005以上
#if _MSC_VER >=1500 // VC2008以上
#if _MSC_VER >=1600 // VC2010以上
例如發現_MSC_VER大於等於1400時,我們可以#include <intrin.h>。然後再利用_MSC_VER進一步判斷__cpuid、__cpuidex的支持性。
三、用條件編譯判斷64位模式(_WIN64)
使用_WIN64這個預處理宏可用來判斷目標平台是不是64位。
雖然在編譯x64平台的程序時,編譯器會自動推導出_WIN64。但是Visual Studio的語法高亮不清楚這些,它有可能仍是按32位代碼來做語法高亮。所以,建議還是手動在項目的預處理宏中增加_WIN64。
四、32位下用內嵌匯編實現__cpuidex函數
在32位模式下,我們可以使用內嵌匯編來實現__cpuidex函數。代碼如下——
[cpp] view plain
void __cpuidex(INT32 CPUInfo[4], INT32 InfoType, INT32 ECXValue)
{
if (NULL==CPUInfo) return;
_asm{
// load. 讀取參數到寄存器
mov edi, CPUInfo; // 准備用edi定址CPUInfo
mov eax, InfoType;
mov ecx, ECXValue;
// CPUID
cpuid;
// save. 將寄存器保存到CPUInfo
mov [edi], eax;
mov [edi+4], ebx;
mov [edi+8], ecx;
mov [edi+12], edx;
}
}
五、全部代碼
全部代碼——
[cpp] view plain
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#if _MSC_VER >=1400 // VC2005才支持intrin.h
#include <intrin.h> // 所有Intrinsics函數
#endif
char szBuf[64];
INT32 dwBuf[4];
#if defined(_WIN64)
// 64位下不支持內聯匯編. 應使用__cpuid、__cpuidex等Intrinsics函數。
#else
#if _MSC_VER < 1600 // VS2010. 據說VC2008 SP1之後才支持__cpuidex
void __cpuidex(INT32 CPUInfo[4], INT32 InfoType, INT32 ECXValue)
{
if (NULL==CPUInfo) return;
_asm{
// load. 讀取參數到寄存器
mov edi, CPUInfo; // 准備用edi定址CPUInfo
mov eax, InfoType;
mov ecx, ECXValue;
// CPUID
cpuid;
// save. 將寄存器保存到CPUInfo
mov [edi], eax;
mov [edi+4], ebx;
mov [edi+8], ecx;
mov [edi+12], edx;
}
}
#endif // #if _MSC_VER < 1600 // VS2010. 據說VC2008 SP1之後才支持__cpuidex
#if _MSC_VER < 1400 // VC2005才支持__cpuid
void __cpuid(INT32 CPUInfo[4], INT32 InfoType)
{
__cpuidex(CPUInfo, InfoType, 0);
}
#endif // #if _MSC_VER < 1400 // VC2005才支持__cpuid
#endif // #if defined(_WIN64)
// 取得CPU廠商(Vendor)
//
// result: 成功時返回字元串的長度(一般為12)。失敗時返回0。
// pvendor: 接收廠商信息的字元串緩沖區。至少為13位元組。
int cpu_getvendor(char* pvendor)
{
INT32 dwBuf[4];
if (NULL==pvendor) return 0;
// Function 0: Vendor-ID and Largest Standard Function
__cpuid(dwBuf, 0);
// save. 保存到pvendor
*(INT32*)&pvendor[0] = dwBuf[1]; // ebx: 前四個字元
*(INT32*)&pvendor[4] = dwBuf[3]; // edx: 中間四個字元
*(INT32*)&pvendor[8] = dwBuf[2]; // ecx: 最後四個字元
pvendor[12] = '\0';
return 12;
}
// 取得CPU商標(Brand)
//
// result: 成功時返回字元串的長度(一般為48)。失敗時返回0。
// pbrand: 接收商標信息的字元串緩沖區。至少為49位元組。
int cpu_getbrand(char* pbrand)
{
INT32 dwBuf[4];
if (NULL==pbrand) return 0;
// Function 0x80000000: Largest Extended Function Number
__cpuid(dwBuf, 0x80000000);
if (dwBuf[0] < 0x80000004) return 0;
// Function 80000002h,80000003h,80000004h: Processor Brand String
__cpuid((INT32*)&pbrand[0], 0x80000002); // 前16個字元
__cpuid((INT32*)&pbrand[16], 0x80000003); // 中間16個字元
__cpuid((INT32*)&pbrand[32], 0x80000004); // 最後16個字元
pbrand[48] = '\0';
return 48;
}
int _tmain(int argc, _TCHAR* argv[])
{
//__cpuidex(dwBuf, 0,0);
//__cpuid(dwBuf, 0);
//printf("%.8X\t%.8X\t%.8X\t%.8X\n", dwBuf[0],dwBuf[1],dwBuf[2],dwBuf[3]);
cpu_getvendor(szBuf);
printf("CPU Vendor:\t%s\n", szBuf);
cpu_getbrand(szBuf);
printf("CPU Name:\t%s\n", szBuf);
return 0;
}
六、兼容性說明
VC編譯器對32/64位的支持性——
32位:VC6是最早支持編譯32位Intrinsics函數的。
64位:VC2005是最早支持編譯64位Intrinsics函數的。
本文方法在32位編譯器下的兼容性——
__cpuid:兼容VC6(或更高)。
__cpuidex:兼容VC6(或更高)。
本文方法在64位編譯器下的兼容性——
__cpuid:兼容VC2005(或更高)。
__cpuidex:兼容VC2010(或更高)。
C. vc判斷是32位編譯還是64位編譯判斷是debug編譯還是release編譯
1.判斷是debug編譯還是release編譯。
如果_DEBUG定義了表示是debug編譯,否則是release編譯。
2.判斷是32位編譯還是64位編譯。
在 Win32 配置下,_WIN32 有定義,_WIN64 沒有定義。在 x64 配置下,兩者都有定義。即在 VC 下,_WIN32 一定有定義。
因此,WIN32/_WIN32 可以用來判斷是否 Windows 系統(對於跨平台程序),而 _WIN64 用來判斷編譯環境是 x86 還是 x64。附一個表:
常量\定義 預定義選項 Windows.h VC編譯器
WIN32 Win32 √(minwindef.h) ×
_WIN32 × × √
_WIN64 × × x64
最後附上根據相應編譯情況,進行有條件的鏈接相應靜態庫的示例代碼,其實就是一些宏定義語句的使用:
[cpp] view plain在CODE上查看代碼片派生到我的代碼片
#include "json/json.h"
#ifdef _DEBUG
#ifndef _WIN64
#pragma comment(lib,"json/json_mtd.lib")
#else
#pragma comment(lib,"json/json_mtd_x64.lib")
#endif
#else
#ifndef _WIN64
#pragma comment(lib,"json/json_mt.lib")
#else
#pragma comment(lib,"json/json_mt_x64.lib")
#endif
#endif
using namespace Json;