C语言怎么取CPU的各项信息?

 我来答
geniepengsz
推荐于2017-10-04 · TA获得超过2万个赞
知道大有可为答主
回答量:1.2万
采纳率:97%
帮助的人:2289万
展开全部

  X86处理器的型号,信息处理器家庭,高速缓存尺寸,时钟速度(频率)和制造商codename 等,存放在处理器的CPU ID寄存器组中。

  通过执行CPU ID指令集查询,即可获取处理器的相关信息。CPU ID汇编指令使用使用eax作为输入参数(有时也用到ecx),eax、ebx、ecx、edx作为输出参数。

示例汇编代码如下:

mov    eax, 1
cpuid

  在C语言中(VC6以上)实现方法为:

  32位模式下,可使用内嵌汇编来调用cpuid指令;64位模式下,VC编译器不支持内嵌汇编,此时可使用微软提供的Intrinsics函数,来执行cpuid指令,该函数支持32位和64位,该函数包含在 <intrin.h>中。
CPUID指令的对应Intrinsics函数为如下两个:

  void __cpuid(
  int CPUInfo[4],
  int InfoType
);

  void __cpuidex(
  int CPUInfo[4],
  int InfoType,
  int ECXValue
);

  其中InfoType参数是CPUID指令的eax参数,即功能ID。ECXValue参数是CPUID指令的ecx参数,即子功能ID。CPUInfo参数用于接收输出的eax, ebx, ecx, edx这四个寄存器。
  早期的CPUID功能只要一个功能ID参数(eax),这时使用__cpuid函数。后来CPUID的功能扩展,又加了一个子功能ID(ecx)参数,这时用__cpuidex。64位环境下包含 <intrin.h>后直接调用两个系统库函数即可。

对32位环境,用内嵌汇编可自定义__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;
      }
}

  利用系统库函数或是自定义的__cpuid,__cpuidex函数,获取处理器信息的2个示例代码如下:

//取得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;
}

  更多CPUID的指令的细节查阅X86处理器公司的技术文件或CPUID规范可获取,这里不一一列举。

匿名用户
2013-08-14
展开全部
intel IA32架构下CPU提供了获取CPU信息的指令CPUID,用该指令能获取CPU信息,使用方法和说明如下。要注意的是,一下如有小于号的,都不是英文的小于号,要用都得该为英文的小于号。 1、什么是cpuid指令 CPUID指令是intel IA32架构下获得CPU信息的汇编指令,可以得到CPU类型,型号,制造商信息,商标信息,序列号,缓存等一系列CPU相关的东西。 2、cpuid指令的使用 cpuid使用eax作为输入参数,eax,ebx,ecx,edx作为输出参数,举个例子: __asm { mov eax, 1 cpuid ... } 以上代码以1为输入参数,执行cpuid后,所有寄存器的值都被返回值填充。针对不同的输入参数eax的值,输出参数的意义都不相同。 为了更好的在C++中使用cpuid指令,可以使用类对指令进行封装,在类中定义一个专门的函数负责cpuid的执行,他需要一个输入参数。还需要定义四个成员变量存储cpuid执行以后返回来的值。由于这四个寄存器都是32位长的,可以使用unsinged long 类型变量存储。 typedef unsigned long DWORD class CPUID { public: ... private: void Executecpuid(DWORD eax); // 用来实现cpuid DWORD m_eax; // 存储返回的eax DWORD m_ebx; // 存储返回的ebx DWORD m_ecx; // 存储返回的ecx DWORD m_edx; // 存储返回的edx ... } void CPUID::Executecpuid(DWORD veax) { // 因为嵌入式的汇编代码不能识别 类成员变量 // 所以定义四个临时变量作为过渡 DWORD deax; DWORD debx; DWORD decx; DWORD dedx; __asm { mov eax, veax ;将输入参数移入eax cpuid ;执行cpuid mov deax, eax ;以下四行代码把寄存器中的变量存入临时变量 mov debx, ebx mov decx, ecx mov dedx, edx } m_eax = deax; // 把临时变量中的内容放入类成员变量 m_ebx = debx; m_ecx = decx; m_edx = dedx; } 这样就可以通过直接调用Executecupid()函数的方式来执行cpuid指令了,返回值存在类成员变量m_eax, m_ebx, m_ecx和m_edx中。 3、获得CPU的制造商信息(Vender ID String) 把eax = 0作为输入参数,可以得到CPU的制造商信息。 cpuid指令执行以后,会返回一个12字符的制造商信息,前四个字符的ASC码按低位到高位放在ebx,中间四个放在edx,最后四个字符放在ecx。比如说,对于intel的cpu,会返回一个“GenuineIntel”的字符串,返回值的存储格式为: 31 23 15 07 00 EBX| u (75)| n (6E)| e (65)| G (47) EDX| I (49)| e (65)| n (6E)| i (69) ECX| l (6C)| e (65)| t (74)| n (6E) 因此可以这样实现他: string CPUID::GetVID() { char cVID[13]; // 字符串,用来存储制造商信息 memset(cVID, 0, 13); // 把数组清0 Executecpuid(0); // 执行cpuid指令,使用输入参数 eax = 0 memcpy(cVID, &m_ebx, 4); // 复制前四个字符到数组 memcpy(cVID+4, &m_edx, 4); // 复制中间四个字符到数组 memcpy(cVID+8, &m_ecx, 4); // 复制最后四个字符到数组 return string(cVID); // 以string的形式返回 } 4、获得CPU商标信息(Brand String) 在我的电脑上点击右键,选择属性,可以在窗口的下面看到一条CPU的信息,这就是CPU的商标字符串。CPU的商标字符串也是通过cpuid得到的。由于商标的字符串很长(48个字符),所以不能在一次cpuid指令执行时全部得到,所以intel把它分成了3个操作,eax的输入参数分别是0x80000002,0x80000003,0x80000004,每次返回的16个字符,按照从低位到高位的顺序依次放在eax, ebx, ecx, edx。因此,可以用循环的方式,每次执行完以后保存结果,然后执行下一次cpuid。 string CPUID::GetBrand() { const DWORD BRANDID = 0x80000002; // 从0x80000002开始,到0x80000004结束 char cBrand[49]; // 用来存储商标字符串,48个字符 memset(cBrand, 0, 49); // 初始化为0 for (DWORD i = 0; i<3; i++) // 依次执行3个指令 { Executecpuid(BRANDID + i); memcpy(cBrand + i*16, &m_eax, 16); // 每次执行结束后,保存四个寄存器里的asc码到数组 } // 由于在内存中,m_eax, m_ebx, m_ecx, m_edx是连续排列 // 所以可以直接以内存copy的方式进行保存 return string(cBrand); // 以string的形式返回 } 5、检测CPU特(CPU feature) 现在的intel CPU,台式机的好点的都支持Hyper-Threading了,移动的要支持Speed Sted。这些都是CPU的特性。CPU的特性可以通过cpuid获得,参数是eax = 1,返回值放在edx和ecx,通过验证edx或者ecx的某一个bit,可以获得CPU的一个特性是否被支持。比如说,edx的bit 32代表是否支持MMX,edx的bit 28代表是否支持Hyper-Threading,ecx的bit 7代表是否支持speed sted。下面就是获得CPU特性的例子: bool CPUID::IsHyperThreading() // 判断是否支持hyper-threading { Executecpuid(1); // 执行cpuid指令,使用输入参数 eax = 1 return m_edx & (1<<28); // 返回edx的bit 28 } bool CPUID::IsEST() // 判断是否支持speed step { Executecpuid(1); // 执行cpuid指令,使用输入参数 eax = 1 return m_ecx & (1<<7); // 返回ecx的bit 7 } bool CPUID::IsMMX() // 判断是否支持MMX { Executecpuid(1); // 执行cpuid指令,使用输入参数 eax = 1 return m_edx & (1<<23); // 返回edx的bit 23 } CPU的特性还有很多,这只是平时我们听到比较多的三个,更多的特性请参考intel的资料。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式