一、#include头文件或是宏的定义不要放在#include"stdafx.h"的前面,否则会提示warning ,甚至编译失败。
1、
//test.cpp : 定义控制台应用程序的入口点。
//
#include<Windows.h>
#include"stdafx.h"
1>------ 已启动全部重新生成: 项目: test, 配置: Debug Win32 ------
1> stdafx.cpp
1> test.cpp
1>c:\users\hc\documents\visualstudio 2010\projects\test\test\test.cpp(3): warning C4627: “#include<Windows.h>”: 在查找预编译头使用时跳过
1> 将指令添加到“StdAfx.h”或重新生成预编译头
1>c:\users\hc\documents\visualstudio 2010\projects\test\test\test.cpp(160): error C2065: “CHAR”: 未声明的标识符
1> c:\users\hc\documents\visual studio2010\projects\test\test\test.cpp(162): error C3861: “GetUserName”: 找不到标识符
注释:
预编译头,貌似就是指的是StdAfx.h。vs系列编译器貌似已经固定死了就认名为StdAfx.h的头文件为预编译头。
函数GetUserName属于<Windows.h>里。从warning C4627: “#include <Windows.h>”: 在查找预编译头使用时跳过;将指令添加到“StdAfx.h”或重新生成预编译头,可以看出:
vs系列编译器编译一个项目时,先找出main函数所在的cpp文件,并查找该cpp文件里是否有预编译头#include"stdafx.h",如果该cpp文件里有#include"stdafx.h",则先对stdafx.cpp(以及stdafx.h)进行编译(即所谓预编译),再对test.cpp即main函数所在的cpp文件进行编译。(对于不存在main函数的项目,如编译一个dll项目该项目中不存在main函数,只有多个相互独立的类,则编译器该怎么知道先编译哪个cpp文件??)
即“生成”里显示的顺序:
1>------ 已启动全部重新生成: 项目: test, 配置: Debug Win32 ------
1> stdafx.cpp
1> test.cpp
而在main函数所在的cpp文件里排在#include"stdafx.h"的语句被跳过,即不会参加编译。这里由于Windows.h被跳过未被参加编译,故而main函数里被调用的属于<Windows.h>的函数GetUserName编译时会提示error C3861: “GetUserName”: 找不到标识符。
2、
//test.cpp : 定义控制台应用程序的入口点。
//
#definettttt
#include"stdafx.h"
1>------ 已启动全部重新生成: 项目: test, 配置: Debug Win32 ------
1> stdafx.cpp
1> test.cpp
1>c:\users\hc\documents\visualstudio 2010\projects\test\test\test.cpp(3): warning C4603: “ttttt”: 未定义宏或在预编译头使用后定义发生改变
1> 将宏添加到预编译头中,而不是在此处定义
1> c:\users\hc\documents\visual studio2010\projects\test\test\test.cpp(5) : 使用预编译头
注释:
这里宏“ttttt”提示warning C4603: 未定义宏,也是因为#definettttt排在#include"stdafx.h"前面,故而在编译时被跳过而未被参加一起编译了。
附加:
//stdafx.cpp : 只包括标准包含文件的源文件
// test.pch将作为预编译头??
//stdafx.obj 将包含预编译类型信息
#include"stdafx.h"
// TODO:在 STDAFX.H中
// 引用任何所需的附加头文件,而不是在此文件中引用
二、对于一个windows API函数最后实际是用它的ASCII版本函数(即该windows API函数的函数名结尾跟上A)还是用它的宽字符(即unicode)版本函数(即该windows API函数的函数名结尾跟上W),取决于相关设置。
相关设置有两种方式。一种影响范围为整个项目,一种影响范围为一个(含有#include"stdafx.h"的)cpp文件。
一种影响范围为整个项目:
选中一个项目,右键点击属性,跳出窗口里选择字符集来设置。
一种影响范围为一个(含有#include"stdafx.h"的)cpp文件:
假设当前项目-》属性-》字符集里的值为“使用unicode字符集”,而你想在项目里的某些cpp文件上使用多字节字符集编码的字符串,则你可以在stdafx.h里写上一语句:#undefUNICODE,并在那些要使用多字节字符集编码的字符串得cpp文件上写上一语句:#include"stdafx.h"即可。
那么你如何知道刚才的设置已经起作用了呢?
两种方法:
1、 如果你装了VX插件,则鼠标移到一windowsAPI函数上时会有如下显示:
2、 在windowsAPI函数上右键选“转到定义”之后看到当前不是灰色的函数版本即为起作用的函数版本:
假设当前项目-》属性-》字符集里的值为“使用多字节字符集”,而你想在项目里的某些cpp文件上使用unicode字符集编码的字符串,则你可以在stdafx.h里写上一语句:#defineUNICODE,并在那些要使用多字节字符集编码的字符串得cpp文件上写上一语句:#include"stdafx.h"即可。
附加:
1、
至于像#defineUNICODE或是#undefUNICODE一定要放在stdafx.h里才起作用,而直接放在那些要使用多字节字符集编码的字符串得cpp文件上不起作用的原因暂时不知了。反正,程序员自己在cpp文件上定义的宏是可以在该cpp文件上起作用的。例如,在一cpp文件上
// #define ttttt
//
#ifdefttttt
intG_r=5;//没定义宏ttttt时该句就是灰色的,有定义则不是灰的,这说明定义的宏起作用了。
#endif
2、
#ifdefUNICODE
#defineGetUserName GetUserNameW
#else
#defineGetUserName GetUserNameA
#endif// !UNICODE
从上述定义模板设计可以看出,对于一个windows API函数要用它的ASCII版本函数(即该windows API函数的函数名结尾跟上A)还是用它的宽字符(即unicode)版本函数(即该windows API函数的函数名结尾跟上W),是利用定义或是取消定义宏UNICODE,而定义或是取消定义宏MBCS之类的名字不起作用的。
3、
对于在tchar.h里定义的TCHAR数据类型,上述第一种方法对其是起作用的:
如果你装了VX插件,
假设当前项目-》属性-》字符集里的值为“使用多字节字符集”,则鼠标移到TCHAR数据类型上时会有如下显示:
typedefchar TCHAR;
假设当前项目-》属性-》字符集里的值为“使用unicode字符集”,则鼠标移到TCHAR数据类型上时会有如下显示:
typedefwchar_t TCHAR;
上述第二种方法对在tchar.h里定义的TCHAR数据类型是不起作用的,原因暂时不知。原因应该是
在 tchar.h 头文件里,使用 _UNCODE 定义而不是使用UNCODE 定义:
#ifdef _UNICODE
... ...
#define __T(x) L##x /* for UNICODE */
... ...
#else
... ...
#define __T(x) x /* for ANSI */
... ...
#endif
#define _T(x) __T(x)
上述第二种方法只要改为定义或是取消定义宏_UNCODE即可起作用。
参见:
宏UNICODE VS 宏_UNICODE 与 TEXT() VS _T()
4、
对于一个windows API函数来说,
它的ASCII版本函数(即该windows API函数的函数名结尾跟上A)的参数里有一个使用字符串的参数,那么ASCII版本函数使用的字符串只能是char数据类型定义的字符串(即多字节字符集编码的字符串,如char str[20]="asdfg";),而不能使用unicode字符集编码的字符串,即wchar数据类型定义的字符串,如wchar str[20]=L"asdfg"。
它的宽字符(即unicode)版本函数(即该windows API函数的函数名结尾跟上W)亦是如此。
不要以为当前项目-》属性-》字符集里的值为“使用unicode字符集”后,该项目里出现的字符串就都是unicode字符集