条件编译汇编
❶ 为什么会有#ifdef else.endif等条件编译语句
为什么会有#ifdef else.endif等条件编译语句 高级语言主要是相对于汇编语言而言,它并不是特指某一种具体的语言,而是包括了很多编程语言,如目前流行的VB、VC、FoxPro、Delphi等,这些语言的语法、命令格式都各不相同。 高级语言所编制的程序不...
❷ #if是啥意思
#if和#endif是一组同时使用的,叫做条件编译指令。#if与#define、#include等指令一样是由预处理器这个强大的工具处理的,预处理器可以在编译前处理c程序。
使用条件编译指令,如果满足#if后面的条件,就编译#if和#endif之间的程序段,否则不编译。
C语言:
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。
C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。
C语言与C++、C#、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
C语言描述问题比汇编语言迅速、工作量小、可读性好、易于调试、修改和移植,而代码质量与汇编语言相当。C语言一般只比汇编语言代码生成的目标程序效率低10%-20%。因此,C语言可以编写系统软件。
当前阶段,在编程领域中,C语言的运用非常之多,它兼顾了高级语言和汇编语言的优点,相较于其它编程语言具有较大优势。计算机系统设计以及应用程序编写是C语言应用的两大领域。同时,C语言的普适较强,在许多计算机操作系统中都能够得到适用,且效率显着。
C语言拥有经过了漫长发展历史的完整的理论体系,在编程语言中具有举足轻重的地位。
❸ 什么是编译程序和汇编程序
编译程序是把用高级程序设计语言或计算机汇编语言书写的源程序,翻译成等价的机器语言格式目标程序的翻译程序,属于采用生成性实现途径实现的翻译程序。编译程序以高级程序设计语言书写的源程序作为输入,而以汇编语言或机器语言表示的目标程序作为输出;编译出的目标程序通常还要经历运行阶段,以便在运行程序的支持下运行,加工初始数据,算出所需的计算结果。
汇编程序是指把汇编语言书写的程序翻译成与之等价的机器语言程序的翻译程序,是为特定计算机或计算机系列设计的一种面向机器的语言,由汇编执行指令和汇编伪指令组成。汇编程序输入的是用汇编语言书写的源程序,输出的是用机器语言表示的目标程序。采用汇编语言编写程序虽不如高级程序设计语言简便、直观,但是汇编出的目标程序占用内存较少、运行效率较高,且能直接引用计算机的各种设备资源。它通常用于编写系统的核心部分程序,或编写需要耗费大量运行时间和实时性要求较高的程序段。汇编程序主要有简单汇编程序、模块汇编程序、条件汇编程序、宏汇编程序、高级汇编程序几种。
❹ 如何在各个版本的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语言中条件编译和If语句之间的差别,各适用于什么情况
条件编译是C语言中预处理部分的内容,它是编译器编译代码时最先处理的部分,
条件编译里面有判断语句,比如
#if
、#else
、#elif
及
#endif
它的意思是如果宏条件符合,编译器就编译这段代码,否则,编译器就忽略这段代码而不编译,如
#define
A
0
//把A定义为0
#if
(A
>
1)
printf("A
>
1");
//编译器没有编译该语句,该语句不生成汇编代码
#elif
(A
==
1)
printf("A
==
1");
//编译器没有编译该语句,该语句不生成汇编代码
#else
printf("A
<
1");
//编译器编译了这段代码,且生成了汇编代码,执行该语句
#endif
而
if
语句则不然,if
是
C
语言中的关键字,它根据表达式的计算结果来觉定执行那个语句,它里面的每个分支都编译了的,
如
#define
A
0
if
(A
>
1)
printf("A
>
1");
//编译器编译该语句,但因为A
==
0
未执行
else
if(A
==
1)
printf("A
==
1");
//编译器编译该语句,但因为A
==
0
未执行
else
printf("A
<
1");
//编译器编译该语句,因为A
==
0
故执行
所以
简单地讲,条件编译是根据
宏条件
选择性地编译语句,它是编译器在编译代码时完成的;
条件语句是根据条件表达式选择性地执行语句,它是在程序运行时进行的。
❻ c代码条件编译参数怎么通过bat文件定义
以GCC编译器为例,可以分为四步。第一步是预处理,包括语法检查等工作。gcc-Pabc.c第二步由源程序生产汇编语言代码。gcc-Sabc.c会生成abc.s文件,这个文件里就是汇编代码。第三步编译器生成目标代码,一个源文件生成一个目标代码。gcc-cabc.c会生成abc.o第四步连接器从目标代码生成可执行文件。gccabc.o目标代码包括机器码和符号表(函数及变量名)。连接器的主要作用是通过符号表在库文件和其他模块中找到在目标代码中引入或未定义的符号(函数及变量名),将几个目标代码合成可执行文件。
❼ 编译和预编译有什么区别。
预编译又称为预处理,是做些代码文本的替换工作。
处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等
就是为编译做的预备工作的阶段
主要处理#开始的预编译指令
编译(compilation , compile) 1、利用编译程序从源语言编写的源程序产生目标程序的过程。 2、用编译程序产生目标程序的动作。 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。
❽ C语言中条件编译和If语句之间的差别,各适用于什么情况
条件编译是C语言中预处理部分的内容,它是编译器编译代码时最先处理的部分,
条件编译里面有判断语句,比如 #if 、#else 、#elif 及 #endif
它的意思是如果宏条件符合,编译器就编译这段代码,否则,编译器就忽略这段代码而不编译,如
#define A 0 //把A定义为0
#if (A > 1)
printf("A > 1"); //编译器没有编译该语句,该语句不生成汇编代码
#elif (A == 1)
printf("A == 1"); //编译器没有编译该语句,该语句不生成汇编代码
#else
printf("A < 1"); //编译器编译了这段代码,且生成了汇编代码,执行该语句
#endif
而 if 语句则不然,if 是 C 语言中的关键字,它根据表达式的计算结果来觉定执行那个语句,它里面的每个分支都编译了的, 如
#define A 0
if (A > 1)
printf("A > 1"); //编译器编译该语句,但因为A == 0 未执行
else if(A == 1)
printf("A == 1"); //编译器编译该语句,但因为A == 0 未执行
else
printf("A < 1"); //编译器编译该语句,因为A == 0 故执行
所以 简单地讲,条件编译是根据 宏条件 选择性地编译语句,它是编译器在编译代码时完成的;
条件语句是根据条件表达式选择性地执行语句,它是在程序运行时进行的。
❾ 条件编译问题
一般情况下,源程序中所有的行都参加编译。但是有时希望对其中一部分内容只在满足一定条件才进行编译,也就是对一部分内容指定编译的条件,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。
编译是在运行前执行的,比如说只是if else语句可能运行时 有些语句可能就没执行,但在编译阶段它们都经行了编译。
而像你上面的#if #else 则不同 #if NNN 就是指当NNN标示符已经定义过则对程序段statement1进行编译,而statement2和statement3则跳过了。
你可能会问:不用条件编译命令而直接用if语句也能达到要求,用条件编译命令有什么好处呢?的确,此问题完全可以不用条件编译处理,但那样做目标程序长(因为所有语句都编译),而采用条件编译,可以减少被编译的语句,从而减少目标的长度。当条件编译段比较多时,目标程序长度可以大大减少。