VC++编译说明

2023-05-16

1编译步骤    1

2编译源文件    2

2.1 编译器    2

2.2 包含头文件    3

2.3 重复包含    6

2.4 预编译头文件    7

2.4.1 创建    7

2.4.2 使用    8

2.4.3 说明    9

3编译资源    10

3.1 编译    10

3.1.1 输出文件    10

3.1.2 语言    11

3.2 include语句    12

3.3 引用文件    13

4连接    14

5其它    17

5.1 编译目录    17

5.2 编译事件    18

5.3 自定义编译    19

5.4 预定义宏    22

5.4.1 ANSI C 预定义宏    22

5.4.2 微软C++预定义宏    23

5.4.3 应用实例    28

5.5 预处理器操作符    28

5.5.1 #    28

5.5.2 #@    28

5.5.3 ##    28

5.5.4 defined    29

 

1编译步骤

使用Visual C++ 6.0新建一个MFC程序,然后编译。IDE(集成开发环境)下,可以看到编译信息:

1.1 VC++6.0编译信息

可见其编译的基本步骤为:

1、删除项目的临时文件和输出文件;

2、编译资源,即编译rc文件,生成res文件;

3、预编译头文件,生成pch文件;

4、编译各个源文件(*.c*.cpp*.cxx),生成obj文件;

5、链接。具体的就是将objres文件合成为一个exe文件,中间可能还需要一些Lib文件。

注意:EVC3.0EVC4.0的编译步骤与VC++6.0完全一致。VC++6.0之后的版本,其编译步骤发生了变化。第2步的编译资源被移至第4步之后。

从上面的编译步骤可以看到,编译时并没有编译头文件(*.h)。这样是否就意味着不需要头文件了?答案当然是否定的。事实上在编译源文件时,预编译器首先处理#include指令,它会将头文件包含至源文件后再进行编译。编译器是以这种方式使用头文件的,认识到这一点对于理解C/C++编译至关重要。

2编译源文件

VC++6.0里编译就是调用C:\Program Files\Microsoft Visual Studio\VC98\Bin\cl.exe将源文件(*.c*.cpp*.cxx)编译为obj文件。

2.1 编译器

假定1.cpp里有如下代码:

int a = 0;

++a;

int b = a + 1;

显然编译它是没问题的,但是把1.cpp改名为1.c,再次编译就会出问题。为什么?原因很简单:源文件的扩展名为c时,编译器按C语言的语法进行编译,生成C代码;源文件的扩展名为cppcxx时,编译器按C++语言的语法进行编译,生成C++代码。CC++语法还是有一定差别的。

大家都知道C++支持函数重载,如下面两个函数在C++里是允许的:

int fun();

int fun(int a); 

但在C语言里是不允许的。为什么呢?因为C语言编译fun时不会将其更名,一个obj文件里是不能有两个同名函数的。C++语言就不同了,会将这两个函数自动更名。VC++6.0里将fun()更名为?fun@@YAHXZ,将fun(int a)更名为?fun@@YAHH@Z,程序员眼里的一个函数fun在编译器眼里仍是两个。

这样就引来一个问题:如果一个函数funA.c文件里,而程序在.cpp里调用了funA函数会出现什么情况?答案是无法调用:因为funAobj里的名字就是funA,但cpp要连接的funA已经被更名了。为了在cpp里调用c函数,函数声明时需要使用extern "C"语句。如下面代码。

extern "C" int fun();

extern "C"

{

int funcA();

int funcB();

} 

CC++混合编程的时候一定要注意这个问题。

2.2 包含头文件

编译源文件时,若遇到 #include "A.h" 语句,则编译器对头文件的搜索顺序如下:

1#include语句所在文件的目录

如:C:\VC\1.c 里有 #include "A.h",则编译器会在1.c所在目录查找A.h,即在C:\VC下查找A.h

如:C:\VC\1.c 里有 #include "../B.h",则编译器会在1.c所在目录查找../B.h,就是查找C:\VC\..\B.h,即C:\B.h。这里的..表示相对路径,即上一级目录。#include "../B.h"里的斜杠/可以换成反斜杠\,不过因为在双引号里\表示转义字符,所以需要两个反斜杠,即:#include "..\\B.h"。以一个斜杠代替两个反斜杠完全是为了简化;

说明:相对路径可通过vcHelper程序获取,这样较为方便。

2、上一级包含文件所在目录

如:C:\VC\1.c 里有 #include "A.h"。编译器在D:\Test目录下找到了A.h。这个A.h里又有#include "B.h",显然编译器会首先在A.h所在目录D:\Test下查找B.h,如果找不到则会在C:\VC\1.c所在目录继续查找。

3Additional include directories 所列目录下依次进行查找

Additional include directories的设置仅对本项目有效,具体请参考图2.1或图2.2VC++6.0的多个路径之间请以逗号分隔。路径可以使用绝对路径也可以使用相对路径。如:C:/VC,../Share,./Inc表示了三个目录:

C:\VC        绝对路径

..\Share        相对于项目文件(dspvcpvcproj)的相对路径

.\Inc        相对于项目文件(dspvcpvcproj)的相对路径

搜索头文件时,先搜索C:\VC目录,再搜索..\Share目录,最后搜索.\Inc目录。

2.1 VC++6.0 Additional include directories

2.2 VC++7.0 Additional include directories

4、在Standard Include Paths里依次进行查找

Standard Include Paths的设置对所有VC++项目都有效。

VC++6.0下,单击【Tools】菜单下的【Option】菜单项,然后进入Directories页面,如下图所示。

2.3 VC++6.0 Standard Include Paths

VC++7.0下,单击【Tools】菜单下的【Option】菜单项。显示界面如下图所示。

 

2.4 VC++7.0 Standard Include Paths

以上讨论的是#include ""语句,如果是 #include <>,则对头文件的查找顺序将是上面的第 3、4步。

建议:

1、如果是自己写的头文件,请使用#include ""语句,并使用相对路径;

2、如果是系统的头文件,如:stdio.h,请使用#include <>语句。

2.3 重复包含

假如1.cpp里包含了头文件A.hB.h,这两个头文件又都包含了C.h。显然编译1.cpp时,C.h将被包含两次。C.h里的结构、类定义也会出现两次,编译器会认为这些结构、类被重复定义了,从而导致编译失败。

解决办法有两个

1、增加#ifndef ... #define ... #endif

如:在C.h里增加如下代码:

//C.h

#ifndef __C_H__

#define __C_H__

//以下是C.h的文件内容

... ... ...

//最后别忘了#endif

#endif //__C_H__ 

编译器编译1.cpp,第二次包含C.h的时候,因为__C_H__已经被定义了,因此会舍弃第二次包含的内容。

该方法要保证每个头文件里的__C_H__都不相同,否则会导致某两个头文件不能同时被包含。

2、增加#pragma once语句

这个方法比较简单,直接在C.h里增加#pragma once即可。美中不足的是:并不是所有的编译器都支持这条指令。所以,采用其它C/C++编译器的时候要注意这一点。

2.4 预编译头文件

假如有多个源文件都包含了windows.h文件。这个头文件非常大,每次编译都比较耗时。有几个源文件包含了它,它就要被编译几次。显然这样的编译效率是相当低的。能不能只编译一次这样的头文件?答案是肯定,那就是使用预编译头文件。即在编译源文件之前,先把windows.h编译出来生成pch文件。在编译源文件的时候,编译器遇到windows.h时将不再编译,而是直接使用pch文件。这个pch就是预编译头文件。

2.4.1 创建

正如前面所说的,编译器是不会直接编译头文件的。因此要预编译头文件,需要指定一个源文件来完成编译并生成pch文件。这里假定要预编译windows.h。请创建一个源文件,如:pch.cpp。其内容很简单,就是#include <windows.h>。然后设置pch.cpp的属性,使其创建pch文件。VC++6.0的设置界面如下:

2.5 VC++6.0创建预编译头文件设置

VC++7.0Solution Explorer里,右键单击pch.cpp,然后单击【Properties】菜单项,设置界面如下图所示

2.6 VC++7.0创建预编译头文件设置

2.4.2 使用

创建PCH文件后,需要设置其它的源文件使用它。

VC++6.0的设置界面如下。

2.7 VC++6.0使用预编译头文件设置

VC++7.0Solution Explorer里,选择要使用预编译头文件的源文件,然后右键单击某一选中文件,或直接右键单击项目然后单击【Properties】菜单项,设置界面如下图所示。注意下图里的my.pch要和图2.6的保持一致,即:创建什么pch文件就使用什么pch文件。

2.8 VC++7.0使用预编译头文件设置

设置多个源文件的属性与设置项目属性的区别:项目就好像国家,源文件就好像各个省。国家出台了政策后,各个省要遵循;但是各个省可以根据自己的情况对政策进行修改。一个源文件的某个属性没有进行设置,则它使用项目的该属性。项目的属性改变后,这个源文件的属性也随之改变。但是如果单独对这个源文件的属性进行了设置,则项目属性的改变对它没有影响。

2.4.3 说明

需要说明以下几点:

1VC++7.0项目里可以使用多个预编译头文件;VC++6.0项目使用多个预编译头文件好像比较困难;

2、创建MFC程序后,预编译头文件设置已经完成,一般无需再设置;

3、一个源文件一旦使用了预编译头文件A.h,则该源文件的第一行一定要包含该头文件。换句话说#include "A.h"之前的代码将被忽略;

4、编译预编译头文件出错后,很难调试。因为不知道编译到哪一行出错了?解决方法就是使用#error#pragma message跟踪编译进度,精确定位编译出错的位置。

3编译资源

Windows程序需要资源,如:图标、光标、对话框……VC++6.0里编译资源就是调用C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe将资源文件(*.rc)编译为res文件。连接程序负责将res文件嵌入exe文件。

3.1 编译

使用记事本创建资源文件1.rc,其内容如下所示。只有一个 ID 100 的字符串。注意:1.rc的编码必须为ANSI

STRINGTABLE DISCARDABLE

{

100 "This is a string"

}

DOS命令窗口,执行如下命令

"C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" C:\1.rc

rc.exe将编译1.rc,并生成1.res。可以使用VC++6.0打开1.res,查看资源内容。

3.1.1 输出文件

默认情况下,1.res1.rc在同一目录。可以通过/fo命令开关更改输出文件,如下命令将更改输出文件为D:\t.res

"C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" /fo"D:\t.res" C:\1.rc

在集成开发环境下,Resource file name 对应的就是/fo命令开关。集成开发环境编译时,会将dspvcproj文件所在目录设置为当前目录,所以如果Resource file name不是绝对路径,那么它就是相对dsp文件目录的相对路径。

3.1 VC++6.0资源设置

3.2 VC++7.0资源设置

3.1.2 语言

1.rc文件修改成如下内容:

STRINGTABLE DISCARDABLE

{

100 "这是一个字符串"

}

使用VC++6.0打开编译生成的res文件,会发现字符串是乱码。因为rc.exe默认使用的语言是美国英语,语言ID0x409。需要将语言ID更改为简体中文的0x804。具体命令如下:

"C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\rc.exe" /fo"D:\t.res" /l804 C:\1.rc

命令开关/l804相当于在1.rc的第一行插入如下语句:

LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

即明确指定语言为简体中文。

如果1.rc的第一行为 LANGUAGE 9,1。即已经指定语言为美国英语,则命令开关/l804是不起任何作用的。

在集成开发环境下,可以通过修改"Language"或"Culture"修改/l命令开关。

3.2 include语句

假定资源文件1.rc里有语句#include "1.rc2",而1.rc2里又有语句#include "2.rc2"。按如下命令进行编译:

3.3 编译资源

则查找2.rc2的顺序如下:

1、包含它的文件(1.rc2)所在目录;

21.rc21.rc包含,所以如果上一步未找到,继续在1.rc所在目录查找;

3、在当前目录查找。上图中,当前目录就是C:\User\yhf

4、由命令开关/i指定的目录。上图中,有两项/i。会依次在D:\inc1D:\inc2中查找。集成开发环境中,可以设定这些目录。

5、如果在集成环境编译,还会在设置的Include目录中查找。至于它的实现,笔者猜测:集成开发环境调用rc.exe时,将Include目录添加至/i命令开关。

3.3 引用文件

有些资源,如图标,其实就是引用的图标文件,如下面的语句:

IDR_MAINFRAME ICON DISCARDABLE "res\\t6.ico"

假如上面一行语句位于2.rc2,那么查找res\t6.ico的顺序如下:

1、被编译资源文件所在目录。注意:rc.exe不会查找2.rc21.rc2所在目录,它会认为这条语句位于被编译的资源文件(1.rc)内。

2、当前目录;

3、由命令开关/i指定的目录。上图中,有两项/i。会依次在D:\inc1D:\inc2中查找。集成开发环境中,可以设定这些目录。

4、如果在集成环境编译,还会在设置的Include目录中查找。

4连接

VC++6.0里连接就是调用C:\Program Files\Microsoft Visual Studio\VC98\Bin\link.exe将编译生成的objres合成为一个exe文件或dll文件。

连接的时候可能还需要其他程序员生成的obj文件和lib文件,使用这些文件的方法有三种。

1、增加该文件至VC项目

4.1 增加文件至项目

该方法的优点就是简单,缺点是不灵活。如这个方法很难处理这个要求:对于Debug版本需要连接TestD.lib,对于Release版需要连接Test.lib

2、修改项目设置

首先增加文件,如图4.2和图4.3所示。

如果需要,还可以指定 Additional library path。如图4.2和图4.4所示。VC++6.0连接程序时,首先在项目目录(即dsp、vcp、vcproj文件所在目录)下查找 Func.obj 和 Test.lib,其次在Additional library path下查找,最后在标准目录下查找。标准库文件目录的设置请参考图2.3和图2.4。

 

4.2 VC++6.0增加库文件及设置库文件目录

4.3 VC++7.0增加库文件

4.4 VC++7.0设置库文件目录

3、在头文件或源文件中,插入如下代码:

#pragma comment(lib, "Test.lib")            //连接时使用 Test.lib。

接着指定 Additional library path,请参考方法2里的描述。连接器查找 Test.lib 时,其查找顺序与第 2 种方法相同。

这种方法非常灵活,请见下面的代码。其含义为:Debug版本下连接TestD.lib,Release版本下连接Test.lib。

#ifdef _DEBUG

#pragma comment(lib, "TestD.lib")

#else

#pragma comment(lib, "Test.lib")

#endif 

说明:

1、这种方法不能指定obj文件;

2、#pragma comment还可指定绝对路径和相对路径,但是建议不要这样做。

5其它

5.1 编译目录

编译、连接的时候会产生大量的文件,可以指定这些文件的存放路径。

临时目录用来存放编译过程中产生的文件,如:pchobjres文件。输出目录用来存放最终生成的exedll文件。这两个目录的设置如下图所示。注意它们可以是绝对路径,也可以是相对于dspvcpvcproj文件的相对路径。

5.1 VC++6.0临时、输出目录设置

5.2 VC++7.0临时、输出目录设置

建议将临时、输出目录设置为Temp,便于查找、删除这些文件。

还可以指定目标文件,请参考下图。

5.3 VC++6.0设置目标文件

5.4 VC++7.0设置目标文件

5.2 编译事件

编译的时候有三个事件:

1Pre-Build

开始编译、连接的时候发生该事件。VC++7.0以上的版本才支持此事件。

2Pre-Link

编译完毕,准备连接的时候发生该事件。

3Post-Build

编译、连接都结束的时候发生该事件。

假如需要在程序编译完成的时候将exe文件移动到c:\,可在Post-Build里增加DOS命令:move $(TargetPath) c:\。具体的设置请参考下图。

5.5 VC++6.0增加编译后处理命令

5.6 VC++7.0增加编译后处理命令

$(TargetPath)是编译时产生的环境变量,其它的环境变量及含义见下表

环境变量

$(MSDEVDIR)

Microsoft Developer目录,如:C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98

$(IntDir) 

临时目录

$(OutDir) 

输出目录

$(TargetPath) 

目标文件,包括路径

$(TargetDir) 

目标文件所在目录

$(TargetName)

目标文件名,不包括路径和扩展名

5.3 自定义编译

有没有想过在VC++6.0里编译VC#代码?有了Custom Build一切皆有可能。假定有如下VC#代码,存在于文件1.cs

using System;

using System.Windows.Forms;

static class Program

{

static void Main()

{

MessageBox.Show("Hello VC#");

}

}

请将1.cs添加至VC++6.0工程,并设置其Custom Build属性:

Commands有两条命令,第一行为:

C:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe /out:$(InputDir)\$(InputName).exe $(InputPath)

其实就是调用csc程序,编译1.cs文件,生成1.exe文件。环境变量$(InputPath)就是1.cs相对于dsp文件的路径(包括文件名)。环境变量$(InputDir)$(InputPath)的目录部分。环境变量$(InputName)1.cs的文件名,不包括扩展名,其实就是1了。$(InputDir)\$(InputName).exe其实就是与1.cs在同一目录下的文件1.exe

第二行命令为$(InputDir)\$(InputName).exe,其实就是编译结束后运行这个程序。

Outputs里为输出文件,这里就是$(InputDir)\$(InputName).exe了。

编译后,可以看到运行结果。

5.7 编译VC#

可以猜测到Custom Build的编译步骤:

1、删除输出文件,这里就是1.exe

2、设置当前目录为dsp所在目录;

3、设置环境变量;

4、调用Commands里面的命令。命令的输出全部被重定向至VC++6.0Output窗口,这样就可以在IDE里查看编译结果。

 

5.4 预定义宏

对于VC++而言,预定义宏分为两大类:ANSI C 预定义宏、微软C++预定义宏。前者被绝大多数C++编译器支持,后者只被微软的VC++支持。

5.4.1 ANSI C 预定义宏

__DATE__

文件的修改日期(本地时间)asctime的返回值

"Oct 31 2009"

__FILE__

文件名,ANSI编码。编译时/FC控制是否含目录。

下面的__WFILE__将是Unicode编码的文件名

#define WIDEN2(x) L ## x

#define WIDEN(x) WIDEN2(x)

#define __WFILE__ WIDEN(__FILE__)

"c:\\vcproj\\a.c"

__LINE__

所在的行号,是10进制的整数。可以被#line预编译指令修改

5

__STDC__

表示编写的C代码必须符合ANSI C标准。不能编译C++代码。

 

__TIME__

文件的修改时刻(本地时间)

"12:48:06"

__TIMESTAMP__

文件的修改日期时刻(本地时间)

"Sat Oct 31 12:48:06 2009"

 

5.4.2 微软C++预定义宏

_ATL_VER 

ATL版本

_CHAR_UNSIGNED

char为无符号。指定/J后,该宏被定义

__CLR_VER 

CLR(common language runtime)版本,其格式为Mmmbbbbb

M 是主版本号

mm 是次版本号

bbbbb 是编译版本号

__cplusplus_cli 

Defined when compiling with /clr, /clr:pure, or /clr:safe. Value of __cplusplus_cli is 200406. __cplusplus_cli is in effect throughout the translation unit.

__COUNTER__ 

0开始,出现一次增加1。可以用来产生读一无二的变量名:

// pre_mac_counter.cpp

#include <stdio.h>

#define FUNC2(x,y) x##y

#define FUNC1(x,y) FUNC2(x,y)

#define FUNC(x) FUNC1(x,__COUNTER__)

 

int FUNC(my_unique_prefix);

int FUNC(my_unique_prefix);

int main()

{

my_unique_prefix0 = 0;

printf_s("\n%d",my_unique_prefix0);

my_unique_prefix0++;

printf_s("\n%d",my_unique_prefix0);

} 

__cplusplus 

如果使用C++编译器,则该宏被定义

_CPPLIB_VER

Defined if you include any of the C++ Standard Library headers; reports which version of the Dinkumware header files are present.

_CPPRTTI

编译开关/GR被打开时,该宏被定义,表示支持运行时类型信息Run-Time Type Information

_CPPUNWIND

Defined for code compiled with /GX (Enable Exception Handling).

_DEBUG

Defined when compiling with /LDd, /MDd, and /MTd.

_DLL 

Defined when /MD or /MDd (Multithread DLL) is specified. 

__FUNCDNAME__ 

Valid only within a function and returns the decorated name of the enclosing function (as a string). __FUNCDNAME__ is not expanded if you use the /EP or /P compiler option.

__FUNCSIG__ 

Valid only within a function and returns the signature of the enclosing function (as a string). __FUNCSIG__ is not expanded if you use the /EP or /P compiler option.

On a 64-bit operating system, the calling convention is __cdecl by default. 

__FUNCTION__ 

Valid only within a function and returns the undecorated name of the enclosing function (as a string). __FUNCTION__ is not expanded if you use the /EP or /P compiler option.

_INTEGRAL_MAX_BITS  

Reports the maximum size (in bits) for an integral type. 

_M_ALPHA 

Defined for DEC ALPHA platforms (no longer supported). 

_M_CEE 

Defined for a compilation that uses any form of /clr (/clr:oldSyntax, /clr:safe, for example).

_M_CEE_PURE 

Defined for a compilation that uses /clr:pure. 

_M_CEE_SAFE 

Defined for a compilation that uses /clr:safe. 

_M_IX86 

Defined for x86 processors. See Values for _M_IX86 for more details.

_M_IX86 = 300        /G3    80386

_M_IX86 = 400        /G4    80486

_M_IX86 = 500        /G5    Pentium

_M_IX86 = 600        /G6    Pentium Pro, Pentium II, and Pentium III

_M_IX86 = 600        /GB    Blend(Default. Future compilers will emit a different value to

                    reflect the dominant processor.)

_M_IA64 

Defined for Itanium Processor Family 64-bit processors.

_M_IX86_FP 

Expands to a value indicating which /arch compiler option was used:

0 if /arch was not used.

1 if /arch:SSE was used.

2 if /arch:SSE2 was used.

See /arch (Minimum CPU Architecture) for more information. 

_M_MPPC  

Defined for Power Macintosh platforms (no longer supported).

_M_MRX000 

Defined for MIPS platforms (no longer supported). 

_M_PPC 

Defined for PowerPC platforms (no longer supported). 

_M_X64 

Defined for x64 processors. 

_MANAGED 

Defined to be 1 when /clr is specified. 

_MFC_VER

MFC的版本

0x0600        VC++6.0/EVC3.0/4.0

0x0700        VC++7.0(VC2002)

0x0710        VC++7.1(VC2003)

0x0800        VC++8.0(VC2005)

0x0900        VC++9.0(VC2008)

_MSC_EXTENSIONS 

This macro is defined when compiling with the /Ze compiler option (the default). Its value, when defined, is 1.

_MSC_VER

VC++的版本

1100    VC++5.0

1200    VC++6.0/EVC3.0

1201    EVC4.0

1300    VC++7.0(VC2002)

1310    VC++7.1(VC2003)

1400    VC++8.0(VC2005)

1500    VC++9.0(VC2008)

__MSVC_RUNTIME_CHECKS

Defined when one of the /RTC compiler options is specified.

_MT 

Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd (Multithreaded) is specified.

_NATIVE_WCHAR_T_DEFINED

Defined when /Zc:wchar_t is used.

_OPENMP

Defined when compiling with /openmp, returns an integer representing the date of the OpenMP specification implemented by Visual C++.

_VC_NODEFAULTLIB  

Defined when /Zl is used; see /Zl (Omit Default Library Name) for more information.

_WCHAR_T_DEFINED 

Defined when /Zc:wchar_t is used or if wchar_t is defined in a system header file included in your project.

_WIN32 

Defined for applications for Win32 and Win64. Always defined.

_WIN64 

Defined for applications for Win64.

_Wp64 

Defined when specifying /Wp64.

UNDER_CE

_WIN32_WCE 

WinCE的版本

5.4.3 应用实例

下面的预处理指令将区分EVC++3.0EVC++4.0VC++6.0VC++9.0

#ifdef _WIN32_WCE        //智能设备

    #if _MSC_VER==1200        //EVC3.0

    #elif _MSC_VER==1201        //EVC4.0

    #elif _MSC_VER==1500        //VC++9.0,即VC2008

    #endif

#else

    #if _MSC_VER==1200        //VC++6.0

    #elif _MSC_VER==1500        //VC++9.0,即VC2008

    #endif

#endif

5.5 预处理器操作符

5.5.1 #

增加双引号,如下面的预编译指令

#define STR(x) #x

编译时,STR(123)将被预处理器替换为 "123"

5.5.2 #@

增加单引号,如下面的预编译指令

#define CHR(x) #@x

编译时,CHR(A)将被预处理器替换为 'A'

5.5.3 ##

连接字符串,如下面的预编译指令

#define CAT(x,y) x##y

编译时,CAT(ABC,123) 将被预处理器替换为 ABC123

5.5.4 defined

必须与条件编译语句#if……#elif……#endif一起使用。

如:#ifdef _WIN32_WCE #if defined(_WIN32_WCE) 等价。

如:#if defined(_WIN32_WCE) && _MSC_VER==1200 表示 EVC3.0 编译器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VC++编译说明 的相关文章

  • 值得推荐的C/C++框架和库

    值得学习的C语言开源项目 Libevent libev是一个开源的事件驱动库 xff0c 基于epoll xff0c kqueue等OS提供的基础设施 其以高效出名 xff0c 它可以将IO事件 xff0c 定时器 xff0c 和信号统一起
  • cmake教程4(find_package使用)

    本文主要内容如下 xff1a 1 cmake find package的基本原理 2 如何编写自己的 cmake module模块 3 使用cmake find package 使用不同版本的opencv lib问题 xff08 openc
  • A*算法

    如此好贴 xff0c 不能不转 xff01 原文地址 xff1a http dev gameres com Program Abstract Arithmetic AmitAStar mht 本文版权归原作者 译者所有 xff0c 我只是转
  • 3.5RC_Channel 和 SRV_channel

    前言 这部分是之前在折腾ROVER的时候梳理了一遍 xff0c 但是没有形成记录 xff0c 现在从新从对象的角度来分析一遍 xff0c 包括映射 转换 数据结构 等方面进行梳理 xff1b 数据结构 首先分析的入口是从Rover read
  • CAN通信详解

    本章我们将向大家介绍如何使用STM32自带的CAN控制器来实现两个开发板之间的CAN通讯 xff0c 并将结果显示在TFTLCD模块上 本章分为如下几个部分 xff1a 30 1 CAN简介 30 2 硬件设计 30 3 软件设计 30 4
  • VC中出现的一些小问题的解决办法

    本人用的是vc6 0的 xff0c 在实际调试过程中出现一些小的问题 xff0c 通过网上查询资料得以解决 xff0c 特此在此整理下 xff0c 方便后者参考 第一问题 xff1a 程序源码编写完成后编译没有问题 xff0c 而链接时出现
  • C++编译报错`XXX‘被多次定义总结;未定义的引用等等

    1 C 43 43 编译报错 96 XXX 被多次定义总结 报错原因 xff1a 诸如类似的报错都是因为可能在两个或者多个 cpp文件 h文件定义该全局变量 xff0c 属于重复定义问题 解决办法是 xff1a 在VScode全局搜索该变量
  • C++必备万能头文件“#include<bits/stdc++.h>”

    c 43 43 代码一个简单的头文件 xff1a span class token macro property span class token directive hash span span class token directive
  • Livox SLAM(带LIO+闭环检测优化)

    主题 xff1a Livox雷达LIO 43 闭环检测优化 开源地址 xff1a LiDAR SLAM 该开源为 Livox雷达实现了一个一体化且即用型的 LiDAR 惯性里程计系统 前端基于基于开源里程计框架LIO Livox获取里程计信
  • 大疆livox定制的格式CustomMsg格式转换pointcloud2

    官方livox driver驱动livox雷达发出的点云topic有两种 xff0c 一种是大疆览沃定制的格式CustomMsg格式 xff0c 另一种是将CustomMsg格式 转换过的pointcloud2格式 xff0c 参见 Liv
  • paddlepaddle

    项目用到了paddlespeech2 xff0c 学了几天paddlepaddle xff0c 简单记录一下 文章目录 1 手写数字识别任务2 极简方案构建手写数字识别模型模型设计训练配置训练过程模型测试 3 手写数字识别 之数据处理4 手
  • SC-Lego-LOAM解析(上)

    文章目录 正文imageProjectionfeatureAssociationFeature Extraction 正文 SC Lego LOAM实际上应该并不对应某一篇特定的论文 xff0c 而是韩国KAIST在github开源的代码
  • SC-Lego-LOAM解析(中)

    上回说到经过连续帧间匹配 xff0c 激光odo给出来一个位姿估计 xff0c 但是是存在不断的误差的积累的 xff0c 需要与绝对的参考 xff08 地图 xff09 进行匹配 xff0c 以及进行回环检测和全局位姿优化 这也是正是map
  • SC-Lego-LOAM解析(下)

    回环检测是一个相对独立的模块 xff0c 这里再开一篇专门说明 前面两篇已经说过 xff0c 先对点云做了预处理 xff0c 然后进行连续帧之间的匹配即激光odom xff0c 然后是scan to map匹配 xff0c 并保存关键帧的位
  • Blog文章导航

    文章超链接 为了更快速的找到感兴趣的文章 xff0c 把我之前写的blog做一个简单的归类 xff1a 一 Nuttx相关 关于Nuttx的开发环境搭建类的文章 xff1a 1 genromfs 的使用及nuttx下romfs制作 2 nu
  • 关于计算程序耗时的几个方法

    1 一个来自r3live的timer tool工具 xff1a 一个功能丰富的头文件 34 tools timer hpp 34 span class token macro property span class token direct
  • gitpush出现remote: Support for password authentication was removed on August 13, 2021.

    git push 报错 xff1a Username span class token keyword for span span class token string 39 https github com 39 span span cl
  • ubuntu解决github访问速度慢的一个小tip

    一 通过设置hosts来解决 xff1a 登录http tool chinaz com dns 查询以下域名映射 并分别取访问速度较快的一个ip xff0c 比如我的 github span class token punctuation
  • 搞SLAM装完一个新的ubuntu系统后需要的环境配置

    所有的文件上传百度云 xff1a 链接 https pan baidu com s 1xheyHxPwaD8Tb9QJ6SAHUA 提取码 gmt9 一个搞SLAM的小白 xff0c 新装完ubuntu系统后应该配置这些内容 1 换源2 安
  • 四元数、变换矩阵、欧拉角转换关系

    四元数to变换矩阵 Eigen span class token double colon punctuation span Quaterniond span class token function quaternion span spa

随机推荐

  • 队列queue最简单的复制拷贝方式

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • 影单:分享一下最近在看的一些电影

    1 千与千寻 电影讲的是少女千寻随爸爸妈妈搬去新的城市 xff0c 开车迷路 xff0c 进入了一个神秘隧道 xff0c 隧道另一边有个风情小镇 xff0c 爸爸妈妈没抵制得了食物的诱惑 xff0c 大吃特吃变成了猪 那是个妖怪的世界 xf
  • conda相关

    安装 ubuntu 18 04 安装conda环境 及 创建虚拟环境 创建虚拟环境 conda create span class token operator span n your env name python span class
  • 几种PCL点云显示方式

    注意添加头文件 xff1a span class token macro property span class token directive hash span span class token directive keyword in
  • 复盘一下slam中常用的几种点云类型

    使用livox雷达常涉及至少3种点云格式 xff0c 一个是livox官方定义的custom格式 xff0c 另外两个就是激光 视觉常用的pcl类型和ros类型 之前总结过Livox雷达驱动程序发布点云格式CustomMsg和pcl Poi
  • [Python]-使用Requests模拟登录

    文章目录 登录说明session操作data序列化 示例代码登录流程验证 在 使用Requests进行HTTP请求与文件上传下载 中介绍了requests库的常用方法 xff0c 本章介绍如何使用request进行用户登录 登录说明 一般页
  • mloam

    以读 pcd xff1a 读取4个激光雷达数据 xff0c input estimator span class token punctuation span span class token function inputCloud spa
  • ROS 工作空间下编译库文件,安装库头文件到devel文件夹

    Hello xff0c 欢迎来到我的博客 我们在ROS工作空间下编程时 xff0c 可能会出现这一种情况 xff1a 我们在一个package下写了一个库 xff0c 而在另一个package要引用这个库 这个时候该怎么处理呢 xff1f
  • js打开新页面的两种方式

    1 点击某一个链接之后跳转到新页面显示 window open http www baidu com blank 2 需要刷新当前页面或者覆盖当前页面 window open http www baidu com self
  • ROS入门教程的学习与总结

    ROS入门教程的学习与总结 1 安装ROS环境2 创建ROS空间3 创建ROS package4 catkin清除命令5 待续 1 安装ROS环境 ROS官网安装参考链接 Linux版本如果是16 04 安装ROS Kinect版本 ava
  • vins-fusion 怎么输出文件? vio_global,vio.txt,vio.csv内容与位置的修改

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 目录 vins fusion 怎么输出文件 xff1f vio global vio txt vio csv内容与位置的修改1 vio g
  • ubuntu18.04安装、使用evo

    ubuntu18 04安装evo 1 切换python版本2 安装pip33 安装evo4 自带test测试5 evo工具介绍6 evo使用6 针对不同数据集的格式以及evo命令 官方连接 xff1a https github com Mi
  • RTKLIB源码及介绍

    目录 1 官网翻译 2 文件下载 1 官网翻译 RTKLIB xff1a 用于 GNSS 定位的开源程序包 下载 版本 日期 适用于 Windows 的二进制 AP 包 带有源程序的完整包 0 2 0 2006 12 16 rtklib 0
  • KITTI数据集基准、转换成tum以及十个groundtruth对应图

    KITTI数据集基准 转换成tum以及十个groundtruth对应图 时间戳的位置gt的位置利用evo进行转换生成kitti基准带时间的tum格式十个路径展示 xff1a 跑vins fusion的时候 xff0c 不知道使用的kitti
  • 【国产可编程逻辑控制器plc调研】

    国产可编程逻辑控制器plc调研 1 高性能PLC xff08 ACxxx系列 xff09 2 中型PLC xff08 AMx00系列 xff09 3 小型PLC xff08 HxU HxS xff09 4 小型紧凑型PLC xff08 Ea
  • 【工业相机接口配置】万兆网口、Camera Link接口、CXP接口

    工业相机接口配置 xff08 万兆网口 Camera Link接口 CXP接口 xff09 万兆网口Camera Link接口CXP接口 目前接触到的工业相机主要有万兆网口 Camera Link接口 CXP接口等不同的接口 另外更常用的是
  • [C++]-yml库yaml-cpp简介

    文章目录 YAML基本语法数据类型对象数组标量引用 yaml cpp库生成器Emitter节点Node数组对象创建解析 yaml cpp是一个yml操作库 YAML YAML YAML Ain t a Markup Language xff
  • 【一篇看全】工业相机常用数据传输协议速率对比(CameraLink,CXP,1/10/100GigE,USB)

    一篇看全 工业相机常用数据传输协议速率对比 xff08 CameraLink xff0c CXP xff0c GigE xff0c USB xff09 CameraLinkCXPGigE10GigE100GigEUSB接口协议速率对比速率换
  • [Unity插件]A* Pathfinding Project:简易教程(一)

    原文链接 xff1a http arongranberg com astar docs getstarted php 插件下载地址 xff1a http pan baidu com s 1eROqaB4 题外话 xff1a 最近想学习一下A
  • VC++编译说明

    目 录 第 1 章 编译步骤 1 第 2 章 编译源文件 2 2 1 编译器 2 2 2 包含头文件 3 2 3 重复包含 6 2 4 预编译头文件 7 2 4 1 创建 7 2 4 2 使用 8 2 4 3 说明 9 第 3 章 编译资源