预编译指令与宏定义#if #elif [defined(), !defined()] #else#ifdef#ifndef #endif// 条件编译
/* 头⽂件防⽌多次被包含 */
#ifndef ZLIB_H
#define ZLIB_H
#endif /* ZLIB_H */
/* ⽤C⽅式来修饰函数与变量 */
#ifdef __cplusplus
extern"C" {
#endif
int add(int a, int b);
int g_nVal = 0;
#ifdef __cplusplus
}
#endif
/* 条件嵌套 */
#ifdef __STDC_VERSION__
# ifndef STDC
# define STDC
# endif
# if __STDC_VERSION__ >= 199901L
# endif
# if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
# define STDC
# endif
#endif
/* ⽇志输出 */
#if defined( DEBUG ) && defined( _MSC_VER )
# include <windows.h>
# define PRINT_LOG OutputDebugString
#else
# define PRINT_LOG printf
#endif
/* MFC中_AfxCopyString的实现*/
inline LPOLESTR AFXAPI _AfxCopyString(LPCTSTR psz)
{
if (psz == NULL)
return NULL;
int cch = lstrlen(psz) + 1;
LPOLESTR pszCopy = NULL;
if ((pszCopy = (LPOLESTR)CoTaskMemAlloc(cch * sizeof(OLECHAR))) != NULL)
{
#ifdef _UNICODE
wcscpy(pszCopy, psz);
#elif !defined(OLE2ANSI)
MultiByteToWideChar(CP_ACP, 0, psz, -1, pszCopy, cch);
#else
lstrcpy(pszCopy, psz);
#endif
}
return pszCopy;
}
#define #undef // 宏定义、宏取消
#define FAR
#define _DEBUG
#define MAX_PATH 260
#define NULL ((void *)0)
#define PASCAL __stdcall
#define CALLBACK FAR PASCAL
#define DEBUG_NEW new
#define new DEBUG_NEW
#define _PUC unsigned char *
#define _CPUC const unsigned char *
#define _PC char *
#define _CPC const char *
#define _UI unsigned int
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define TRACE ::AfxTrace
#define TRACE0(sz) ::AfxTrace(_T("%s"), _T(sz))
#define TRACE1(sz, p1) ::AfxTrace(_T(sz), p1)
#define TRACE2(sz, p1, p2) ::AfxTrace(_T(sz), p1, p2)
#define TRACE3(sz, p1, p2, p3) ::AfxTrace(_T(sz), p1, p2, p3)
// 重新定义FALSE、TRUE、NULL
#undef FALSE
#undef TRUE
#undef NULL
#define FALSE 0
#define TRUE 1
#define NULL 0
/* TCHAR.H */
#ifdef _UNICODE
typedef wchar_t TCHAR;
#define __T(x) L ## x
#define _tmain wmain
#define _tprintf wprintf
#else
typedef char TCHAR;
#define __T(x) x
#define _tmain main
#define _tprintf printf
#endif
#define _TEXT(x) __T(x)
#define _T(x) __T(x)
/* 使⽤OF宏来适配函数参数 */
#ifndef OF
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
int add OF((int a, int b));
/* 宏必须在⼀⾏写完,多⾏写时必须带上 \⾏连接符 */
/* 注意##字符拼接符 */
#define DECLARE_DYNAMIC(class_name) \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const;
/* Debug时可使⽤THIS_FILE变量获得当前⽂件名*/
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
####@// 特殊符号
/* ## 字符拼接符 */
#define Conn(x,y) x ## y
int n = Conn(123,456); //n = 123456;
char* str = Conn("abc","def"); //str = "abcdef";
/* # 加双引号 */
#define ToString(x) #x
#define PrintAge(age) printf("I am " #age " years old.\n") // 注:字符串是可以⽤空格分开写的,编译器会将其合成⼀个字符串;如:printf("Hello " "World" "!")等价于printf("Hello World!") char* str = ToString(12.345); //str= "12.345"
PrintAge(20); // 输出 I am 20 years old.
/* #@ 加单引号 */
#define ToChar(x) #@x
char ch = ToChar(a); //ch='a'
#include #include_next【GNU的⼀个扩展,gcc下可使⽤】// ⽂件包含
#include <stdio.h> // 只搜索系统⽬录
#include "stdafx.h"// 先搜索⼯程当前⽬录,再搜索系统⽬录
#include "../zlib/zconf.h"// 以当前⽂件作为参考来计算
// #include_next为GNU的⼀个扩展,gcc下可使⽤
// #include_next <xx.h> 包含在搜索路径列表中第2次到的xx.h
// 例如:搜索路径顺序为:/usr/local/include,/usr/include
/
/ 如果这两个⽬录下都有signal.h⽂件,将引⽤/usr/include中的那个
#include_next <signal.h>
// 另外#include_next不区分""与<>,都是先搜索⼯程当前⽬录,再搜索系统⽬录
#line指⽰下⼀⾏的⾏号,及当前所在的⽂件;该命令会修改__FILE__、__LINE__的值
该命令是提供给编译器使⽤的,程序员最好不要使⽤该命令,否则会导致调试异常(如:断点打不上等)
#line 100 "myFile.cpp"
printf("File: %s, Line: %d, Function: %s\n", __FILE__, __LINE__ ,__FUNCTION__);
// 输出File: f:\vstest\vstest\myfile.cpp, Line: 101, Function: wmain
#pragma
#pragma once // 防⽌头⽂件重复包含【vc编译器版本:_MSC_VER > 1000时才⽀持#pragma once】
#pragma message ("发布版本请去掉测试代码") // 编译时打印⾃定义信息
#pragma warning(disable: 4102 4235) // 不提⽰C4102、C4235的warning
#pragma warning(once:4385) // C4385警告仅报告⼀次
#pragma warning(error:5038) // C5038警告信息视为错误强制保证:Initialization order(成员变量的初始化顺序要与它们的声明顺序⼀致)
#pragma warning(default: 4310) // 将C4310的警告⾏为到默认状态
#pragma warning(disable:4507 34; once:4385; error:164)
#pragma warning(push) //保存现有警告状态
#pragma warning(push, 3) //保存现有警告状态,并且把warning level设为3
#pragma warning(pop) //弹出栈顶的⼀个警告信息,这对导致push和pop之间所作的⼀切改动取消掉
#pragma comment(lib, "../zlib/zlib.lib") // 链⼊zlib.lib导出库
// ⽬录结构如下:
+-- testStdafx.h
|- Debug
+-- testLib.lib
#pragma comment(lib, __FILE__ "\\..\\" "Debug\\" "testLib.lib") // 若当前⽂件为testStdafx.h,在testStdafx.h中包含⾃⼰的lib⽂件,可以避免外部⼯程⼿动包含test.lib
// 外部⼯程只需要#include "testStdafx.h"即可,如果多个⼯程使⽤testLib.lib,这个做法⾮常⽅便
// 后⾯路径分段个数没有限制,理论上任意多个都⾏
/*#pragma data_seg指定函数存放在*.obj⽂件中的数据段,默认的代码段是.data*/
int i = 0; // 存放在"data"段
#pragma data_seg(".my_data1")
int j = 1; // 存放在"my_data1"段
#pragma data_seg(push, stack1, ".my_data2")
int k = 2; // 存放在"my_data2"段
#pragma data_seg(pop, stack1) // pop stack1 off the stack
int m = 3; // 存放在"my_data1"段
#pragma data_seg()
int n = 4; // 存放在"data"段
/*#pragma code_seg指定函数存放在*.obj⽂件中的代码段,默认的代码段是.text*/
void func1() {} // 存放在text段
#pragma code_seg(".my_data1")
void func2() {} // 存放在my_data1段
#pragma code_seg(push, r1, ".my_data2")
void func3() {} // 存放在my_data2段
#pragma code_seg(pop, r1)
void func4() {} // 存放在my_data1段
#pragma code_seg()
void func5() {} // 存放在text段
/* 除了data_seg和code_seg之外,还有bss_seg与const_seg */
/* bss_seg与const_seg的使⽤与data_seg、code_seg⼀致*/
//shareddata ⼀般⽤于dll中;共享数据必须初始化,否则会放到.BSS段中
#pragma data_seg("shareddata")
int nTotalNum = 0; //nTotalNum可以被多个进程共享
#pragma data_seg()
/* #pragma comment(linker,...)主要⽤来设置链接参数 */
/
* 常见的链接参数详见: */
/*wwwblogs/kekec/archive/2013/04/21/3007277.html中的段的说明 */
// 将flag_data数据段设置为可读、可写、可共享
#pragma comment(linker,"/SECTION:flag_data,RWS")
// 导出extern "C" fnSub函数
#pragma comment (linker, "/EXPORT:_fnSub")
// 导出extern "C" fnAdd函数,并将符号名修改为myfnAdd,同时将导出序号设为1
#pragma comment (linker, "/EXPORT:myfnAdd=_fnAdd,@1")
// 强制包含名为__mySymbol的符号;
// 若要指定多个符号,请在符号名称之间键⼊逗号、分号或空格
#pragma comment(linker, "/include:__mySymbol")
/
* 区别:源码的inline在编译器进⾏预处理的时候就展开了,*/
/* ⽽#Pragma intrinsic却是以⼆进制的⽅式inline进去的 */
// 使⽤内联版本的memset及strlen
#pragma intrinsic(memset, strlen)
/* 使⽤回函数调⽤的strlen */
#pragma function(strlen)
/* 对于不同⽂件中的全局对象、变量,它们的构造函数调⽤顺序是未定义的,取决于具体的编译器,这就可能带来⼀些问题 */
/* compiler、lib、user,初始化优先次序依次降低,但都先于普通的全局变量构造*/
/* 对于必须优先被初始化的对象或变量应使⽤这3个指令 */
/* ⼀个源⽂件只能出现⼀次init_seg 指令 */
#pragma init_seg(compiler)
#pragma init_seg(lib)
#pragma init_seg(user)
#pragma init_seg("user_defined_segment_name") // ⽤户⾃定义名称
// 详见:wwwblogs/kekec/archive/2012/10/31/2748955.html
#pragma pack(push, 4)
#pragma pack(pop)
#pragma optimize("", off) // 关闭代码编译优化
#pragma optimize("", on) // 开启代码编译优化
#pragma inline_recursion(on) // 开启内联递归
#pragma inline_recursion(off) // 关闭内联递归
// 函数堆栈深度超过指定深度,就不进⾏函数内联
#pragma inline_depth(0) // 不进⾏任何内联
#pragma inline_depth(10) // 深度超过10层,不进⾏函数内联
#pragma inline_depth() // 缺省深度值为254
// myheader.h关闭最⼩重新⽣成【见/Gm编译选项】
/* myheader.h起始处 */
#pragma component(minrebuild, off)
/* myheader.h */
#pragma component(minrebuild, on)
/* myheader.h结束处 */
#error// c编译器error命令
#ifndef __cplusplus
#error MFC requires C++ compilation (use a .cpp suffix)
#endif
extern"C"
{
#error "printf error!"
};
visual studio和vs code的区别__VA_ARGS__【变参】新的C99规范中增加的,gcc及vs2005版本以上的ms编译器⽀持该宏
/* vs2008测试 */
#define debug1(...) printf(__VA_ARGS__)
#define debug2(fmt, ...) printf(fmt, __VA_ARGS__)
#define debug3(fmt, ...) printf(fmt, ## __VA_ARGS__)
int a = 10;
const char* chs = "Hello";
debug1("%d %s\n", a, chs); // printf("%d %s\n", a, chs);
debug2("%d %s\n", a, chs); // printf("%d %s\n", a, chs);
debug3("%d %s\n", a, chs); // printf("%d %s\n",a, chs); a前会少⼀个空格
/* 安全调⽤对象的⽅法 */
#define SafeCallFunc(ptr, retType, func, ...) ( (ptr!=NULL)?(ptr->func(__VA_ARGS__)):(retType(0)) )
/* 安全获取对象的成员变量 */
#define SafeGetValue(ptr, val, valType) ( (ptr!=NULL)?(ptr->val):(valType(0)) )
注:__VA_ARGS__前加上##的作⽤在于,当可变参数的个数为0时,将##前⾯多余的逗号去掉,否则会编译不过(vs不加##,也可以编译过)
__FILE__、__LINE__、__FUNCTION__、__DATE__、__TIME__、__TIMESTAMP__
// File: f:\vsconsole1\vsconsole1\vsconsole1.cpp, Line: 9, Function: wmain
// vc6不⽀持__FUNCTION__宏
printf("File: %s, Line: %d, Function: %s\n",__FILE__,__LINE__,__FUNCTION__);
// Date: Sep 19 2013 Time: 22:38:51 TimeStamp: Thu Sep 19 22:38:50 2013
printf("Date: %s Time: %s TimeStamp: %s\n",__DATE__,__TIME__, __TIMESTAMP__);
注:__DATE__、__TIME__、__TIMESTAMP__会被替换成该源⽂件编译成obj⽂件时的⽇期、时间、和unix时间戳
__STDC__、__STDC_VERSION__、__cplusplus
__STDC__ // 当前编译器符合c标准,则该宏的值为1
__STDC_VERSION__ // 当前编译器符合C89, 该宏的值为199409L, 符合C99, 该宏的值为199901L
__cplusplus // 当前编译器符合c++标准,则该宏值为编译器版本号注:vs2017及以后的版本才⽀持,需要加/Zc:__cplusplus编译选项,否则该宏始终为199711L
// C++ pre-C++98: __cplusplus is 1
// C++98: __cplusplus is 199711L
// C++98 + TR1: This reads as C++98 and there is no way to check that I know of
// C++11: __cplusplus is 201103L
// C++14: __cplusplus is 201402L
// C++17: __cplusplus is 201703L
注:ue4.26在windows平台缺省使⽤c++14进⾏编译
_MSC_VER
_MSC_VER = 1928// MS VC++ 16.0 Visual Studio 2019
_MSC_VER = 1910// MS VC++ 15.0 Visual Studio 2017
_MSC_VER = 1900// MS VC++ 14.0 Visual Studio 2015
_MSC_VER = 1800// MS VC++ 12.0 Visual Studio 2013
_MSC_VER = 1700// MS VC++ 11.0 Visual Studio 2012
_MSC_VER = 1600// MS VC++ 10.0 Visual Studio 2010
_MSC_VER = 1500// MS VC++ 9.0 Visual Studio 2008
_MSC_VER = 1400// MS VC++ 8.0 Visual Studio 2005
_MSC_VER = 1310// MS VC++ 7.1 Visual Studio .NET 2003 _MSC_VER = 1300// MS VC++ 7.0 Visual Studio .NET (2002) _MSC_VER = 1200// MS VC++ 6.0 Visual Studio 6.0
_MSC_VER = 1100// MS VC++ 5.0 Visual Studio 97
Product name Codename Internal
version
Supported .NET
Framework versions
Release date
Visual Studio N/A 4.0N/A April 1995
Visual Studio 97Boston 5.0N/A February 1997
Visual Studio 6.0Aspen 6.0N/A June 1998
Visual Studio .NET (2002)Rainier7.0 1.0February 13, 2002
Visual Studio .NET 2003Everett7.1 1.1April 24, 2003
Visual Studio 2005Whidbey8.0 2.0, 3.0November 7, 2005
Visual Studio 2008Orcas9.0 2.0, 3.0, 3.5November 19, 2007
Visual Studio 2010Dev10/Rosario10.0 2.0, 3.0, 3.5, 4.0April 12, 2010
Visual Studio 2012Dev1111.0 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2September 12, 2012
Visual Studio 2013Dev1212.0 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2
October 17, 2013
Visual Studio 2015Dev1414.0 2.0 - 4.6.12015-07-20
Visual Studio 2017Dev1515.0 3.5 - 4.7.22017-03-07
Visual Studio 2019Dev1616.0 3.5 - 4.82019-04-02
WINVER
win32具有良好的向下兼容性,低版本的win32程序可以在后续⾼版本的windows系统上正确运⾏
随着windows版本的升级,更多Windows API被加⼊,为了能在程序中使⽤这些新增的API函数,可以将WINVER宏设定到更⾼的版本,保证程序能编译链接到windows SDK中的这些API;
但与此同时,也带来了新的问题,意味着你的程序只能在更⾼版本的windows上运⾏
Name Release
version
WINVER Architecture NT 4.0 0x0400, ,,
NT 5.0 0x0500,
NT 5.1; NT 5.2
(2003 and x64)
0x0501
0x0502
, ,
NT 5.2 0x0502, ,
NT 6.0 0x0600,
NT 6.0 0x0600, ,
NT 6.1 0x0601,
NT 6.2 0x0602, , (ARMv7) NT 6.3 0x0603, , (ARMv7) NT 10.0 0x0A00
编译时打印出宏的内容
//测试宏
#define PI 3.1415926
#define MAX(a,b) (a)>(b) ? (a) :(b)
//⾸先定义两个辅助宏
#define PRINT_MACRO_HELPER(x) #x
#define PRINT_MACRO(x) #x"="PRINT_MACRO_HELPER(x)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论