stafx.h错误与预编译头详解

VS2019汇编 错误 【 MSB3721】和【A2026】 constant expected 错误 A2026 constant expected E:\masm32\include\winextra.inc 11052 错误 A2026 constant expected E:\masm32\include\winextra.inc 11053 错误 MSB3721 命令“ml.exe /c /nologo /Zi /Fo"Debug\1.obj" /I "E:\masm32\include" /W3 /errorReport:prompt /Ta1.asm”已退出,返回代码为 1... 阅读详情
最近在一个项目中遇到了一个很奇怪的问题,在基于MFC的DLL工程中,一个cpp文件除了在该工程中使用外,在另外一个工程中也会用到,所以及使用了条件编译#ifdef,具体代码如下:
#ifndef PYTHON_ALONE
#include "stdafx.h"
#include <ProUtil.h>
#include <ProMessage.h>
#else
#include <Windows.h>
#include <atlstr.h>
#include <tchar.h>
#endif
但是在编译的时候总是报错:fatal  error  C1019:  unexpected  #else
后来在网上查了好多,最终终于找到问题的症结:都是stafx.h惹的祸!
只需要在这个cpp文件上右键->属性,在预编译头文件选项上选择“不使用预编译头文件”即可。(注意:是这个CPP文件的属性,而不是工程的属性)
stafx.h错误与预编译头详解
其实之前也遇到过stafx.h导致的错误,譬如:
fatal  error  C1010:  unexpected  end  of  file  while  looking  for  precompiled  header.  Did  you  forget  to  add  '#include  "stdafx.h"'  to  your  source?
但是那时也就是根据提示将#include "stafx.h"加上而已,没有深究为什么会出现这样的问题。
下面就详细讲一下stafx.h的意义:
      要讲预编译头文件的作用,要先从头文件的编译原理说起。其实头文件并不神秘,它的全部作用,就是把自己的所有内容直接“粘贴”到相应的#include 语句处。如果不相信的话,不妨做个实验,将一个 cpp 中的所有 #include语句删掉,并将它包含的文件粘贴到相应的位置,你会发现,文件的编译和运行都完全没有受到影响。其实,编译器在编译你的程序的时候,所做的第一件事,也就是展开所有的#include 语句和 #define 语句。
      头文件的出现,固然给书写程序带来了很大方便。可是到了 Windows 时代后,慢慢就呈现出一些问题了。几乎所有的 Windows程序都必须包含 windows.h,而那个文件却硕大无比,将它展开后往所有文件中一粘贴,编译的时候立刻慢得像只蜗牛。
      到了 MFC时代后,情况更为恶劣了。毕竟 C 风格的 Windows 头文件里面包含的还仅仅是函数定义和宏,编译难度不算太大,而 MFC库里面的头文件可都是类声明啊!更何况,一个最简单的工程,都会生成大量的类,需要用到大量的函数。如果工程稍微复杂一些,编译难度可想而知!
      但是,人们惊奇地发现,虽然用到的头文件又多又杂,但是在一个工程中,总有那么一堆头文件,是几乎所有 cpp都必须包含的。那么,可不可以把这些头文件提取出来,只编译一编,然后所有其它 cpp就都能使用呢?没错,这就是预编译头的思想都由来!
      实践证明,使用了预编译头技术后,编译速度大大提高了。可以到你的工程目录下的Debug 或 Release目录中看一看,里面有一个体积极为硕大的 .pch 文件,那就是传说中的“编译之后的预编译头”。
      使用了预编译头技术后,虽然带来了极大地方便,但也造成了一个问题:由于它假定预编译头中包含过的头文件会在所有 cpp中使用,因此它在编译你的 cpp 的时候,就会将预编译头中已经编译完的部分加载到内存中。如果它突然发现你的 cpp居然没有包含预编译头,它就会很郁闷,因为它不知道该如何将已编译完的部分从内存中请出去,整个编译过程就会失败。
      因此,如果你使用了预编译头技术,就必须在所有的 cpp 中包含预编译头。MFC 工程中为你建立了一个默认的预编译头stdafx.h,如果你愿意,也可以在自己的工程中使用其它文件名作为你的预编译头,如果你觉得有必要。
      当然,你也可以不使用预编译头,就像我上面遇到的问题一样,将该文件设置成为不使用预编译头即可。
      下面是我的一个实际工程的BuildLog.htm中的部分信息:
正在创建临时文件“d:\Lab\svn\Core_PDM\Source\ProePDM2005\ProePDM2005\Release\RSP00002939846852.rsp”,其内容为
[
/O2 /GL /I "..\Python25\include" /I "..\ComLIB" /I"..\PDMPython" /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D"PRO_USE_VAR_ARGS" /D "_WINDLL" /D "_AFXDLL" /D "_UNICODE" /D"UNICODE" /FD /EHsc /MD /Yu"stdafx.h"/Fp"Release\ProePDM2005.pch" /Fo"Release\\" /Fd"Release\vc80.pdb"/W3 /c /Wp64 /Zi /TP .\ProePDM2005.cpp
]
正在创建命令行“cl.exe@d:\Lab\svn\Core_PDM\Source\ProePDM2005\ProePDM2005\Release\RSP00002939846852.rsp/nologo /errorReport:prompt”
正在创建临时文件“d:\Lab\svn\Core_PDM\Source\ProePDM2005\ProePDM2005\Release\RSP00002A39846852.rsp”,其内容为
[
/O2 /GL /I "..\Python25\include" /I "..\ComLIB" /I"..\PDMPython" /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D"PRO_USE_VAR_ARGS" /D "_WINDLL" /D "_AFXDLL" /D "_UNICODE" /D"UNICODE" /FD /EHsc /MD /Yc"stdafx.h"/Fp"Release\ProePDM2005.pch" /Fo"Release\\" /Fd"Release\vc80.pdb"/W3 /c /Wp64 /Zi /TP .\stdafx.cpp
]
正在创建命令行“cl.exe@d:\Lab\svn\Core_PDM\Source\ProePDM2005\ProePDM2005\Release\RSP00002A39846852.rsp/nologo /errorReport:prompt”
正在创建临时文件“d:\Lab\svn\Core_PDM\Source\ProePDM2005\ProePDM2005\Release\RSP00002B39846852.rsp”,其内容为
[
/O2 /GL /I "..\Python25\include" /I "..\ComLIB" /I"..\PDMPython" /D "WIN32" /D "_WINDOWS" /D "NDEBUG" /D "_USRDLL" /D"PRO_USE_VAR_ARGS" /D "_WINDLL" /D "_AFXDLL" /D "_UNICODE" /D"UNICODE" /FD /EHsc /MD /Fo"Release\\"/Fd"Release\vc80.pdb" /W3 /c /Wp64 /Zi /TP .\PySw.cpp
]
      在上面的工程中,PySw.cpp文件包含了本文开头的那段代码,但是没有预定义PYTHON_ALONE,将该文件设置为“不使用预编译头”才得以编译通过。所以我们在编译的过程中可以看到,在编译stafx.cpp文件时,使用了/Yc选项,即创建预编译头;在编译ProePDM2005.cpp文件时使用了/Yu选项,即使用预编译头;而在编译PySw.cpp文件时,则没有使用预编译头,但是由于该文件没有PYTHON_ALONE定义,所以在条件编译前几行代码时,会直接将stdafx.h的内容展开,一起编译到PySw.cpp文件中,这点可以从编译之后的obj文件的大小中得到验证,下面是编译之后生成的几个Obj文件大小的截图:
stafx.h错误与预编译头详解
      将代码改为以下形式,并将PySw.cpp文件设置为“使用预编译头”,编译之后的obj文件大小如下图所示
#include "stdafx.h"
#include <ProUtil.h>
#include <ProMessage.h>
//#ifndef PYTHON_ALONE
//#else
//#include <Windows.h>
//#include <atlstr.h>
//#include <tchar.h>
//#endif
stafx.h错误与预编译头详解
      对比两个Obj文件大小的截图可以发现,PySw.cpp使用预编译头时,PySw.obj文件的大小为48KB,而PySw.cpp不使用预编译头时,PySw.obj文件大小为1715KB,差不多相当于将stafx.obj(1976KB)和原来的叠加在一起的结果。
      可以看一下MSDN网站上关于预编译头的使用的部分:
# Makefile : Illustrates the effective use ofprecompiled
OBJS = myapp.obj applib.obj
# List all stable header files in the STABLEHDRS macro.
STABLEHDRS = stable.h another.h
# List the final header file to be precompiled here:
BOUNDRY = stable.h
====================================
 
# Compile myapp
myapp.obj  : myapp.cpp$(UNSTABLEHDRS)  stable.pch
      $(CPP)$(CLFLAGS)/Yu$(BOUNDRY)      myapp.cpp
# Compile applib
applib.obj : applib.cpp $(UNSTABLEHDRS) stable.pch
      $(CPP)$(CLFLAGS)/Yu$(BOUNDRY)      applib.cpp
# Compile headers
stable.pch : $(STABLEHDRS)
      $(CPP)$(CLFLAGS)/Yc$(BOUNDRY)      applib.cpp myapp.cpp
stafx.h错误与预编译头详解

从关系图顶部开始,STABLEHDRS 和BOUNDRY 都是 NMAKE宏,您在这些宏中列出不大可能需要重新编译的文件。只有在预编译头文件 (STABLE.pch)不存在或对两个宏中列出的文件进行更改时,才使用命令字符串

CL /c /W3 /Yc$(BOUNDRY) applib.cpp myapp.cpp

编译这些文件。无论在哪一种情况下,预编译头文件都将只包含来自 STABLEHDRS 宏中所列文件的代码。在 BOUNDRY宏中列出最后一个想预编译的文件。

在这些宏中列出的文件可以是头文件,也可以是 C或 C++ 源文件。

在上面的这个例子中,工程中的预编译头只有头文件,没有与之对应的cpp文件,在我们的工程中stafx.cpp中只有#include "stafx.h"一句,那么我们可不可以也将stafx.cpp删掉呢?其实是可行的。

但是我们把stafx.cpp删掉之后,重新编译,会报类似下面的错:

error C2859:d:\lab\svn\core_pdm\source\proepdm2005\proepdm2005\release\vc80.pdbis not the pdb file that was used when this precompiled header wascreated, recreate the precompiled header.

按照提示,我们需要重新生成预编译头,所以我们先把Debug或Release(此处是Release)文件夹下的pch文件删掉,再重新编译,这时又会报下面的错:

fatal error C1083: Cannot openprecompiled header file: 'Release\ProePDM2005.pch': No such file ordirectory

一般情况下,遇到了pchmissing错误,只需要重新编译即可,但是我们此时却无法通过重新编译来解决这个问题。因为我们把产生pch文件的stafx.cpp删掉了,所以这时候我们需要使用另外的文件产生pch文件。我们可以在另外的cpp文件,如此处的ProePDM2005.cpp文件上右键->属性,在预编译头的选项中设置为"创建预编译头(/Yc)",然后再重新编译就可以了。但是这会导致的结果是pch文件巨大,并且只要ProePDM2005.cpp文件发生了改变,pch文件就会重新生成,没有起到使用预编译头降低编译时间的作用,所以还是把不需要经常修改的文件作为预编译头比较好。下面是这次重新编译之后的结果(PySw.cpp未使用预编译头):

stafx.h错误与预编译头详解
   

  通过以上的总结,我们基本上已经将预编译头的作用和使用时需要注意的事项搞清楚了,这样今后遇到跟stafx.h有关的错误时就不会束手无措了。

(最后吐槽一下Wiz的编辑器,同样的字体同样的字号显示效果却不一样,让人无语啊,得跟老魏提提意见啊!)

参考:
 


AFXDLL的使用方法,作用,技巧之类的 c++是一门好语言,其中的点点滴滴都充满了力量,跟人以无限的瞎想,赶快加入我们的c++生力大军吧 立即下载

相关推荐

金融科技数据源

数字金融开放研究平台

平平淡淡,戒急用忍,一生学闭嘴。 1758

MFC:_AFXDLL

_AFXDLL是一个在VC++的MFC程序中的系统约定宏定义。这个定义本身没有什么意义,只是约定标记了,MFC程序,是使用的静态链接库还是动态链接库。如果定义了这个宏(通常是在工程项目属性中),说明使用的是MFC动态链接,否则为MFC静态链接。在这两种情况下,代码中DECLARE_MESSAGE_MAP的消息映射定义都是存在的,只是有一个细微的差别。这个差别就是,静态链接因为MFC的基础代码在...

weixin_30480075的博客 1113

主流双目相机技术参数横向评测:从ZED到INDEMIND的深度解析

本文对主流双目相机进行了深度横向评测,涵盖ZED、Bumblebee、Leap Motion、DUO 3D及INDEMIND等国内外产品。文章详细解析了分辨率、帧率、视场角、基线等核心参数,并结合科研、机器人导航、无人机、工业检测等典型应用场景,提供了实战选型指南,帮助读者根据具体需求挑选最合适的双目视觉解决方案。

weixin_29212867的博客 641

c++ fatal error C1083: 无法打开预编译头文件:“.\Debug\router.pch”

一、出现此错误首先检查:stdafx.cpp文件上右键——属性,预编译头选“创建”,其它cpp选“使用”。 二、如果是采用这样的设置,还是有错误,重新生成解决方案,重新调试。 三、实在不行的话,步骤/方法右键点击你创建的项目,选择“属性标签”点击属性,弹出“项目属性页”,在左侧找到以下位置  配置属性 -->  C/C++  --> 预编译头,并选择它:在右边的菜单中选择 “创建/使用预编译头

lishan9133的专栏 8144

无人机VS地面机器人:用AirSim和Gazebo玩转ROS2仿真的5个实战场景对比

本文深度对比了ROS2生态中两大仿真工具AirSim和Gazebo在无人机与地面机器人应用中的表现。通过电力巡检、仓库调度、SLAM建图等5个实战场景,分析了两者在视觉保真度、物理精度、开发效率等方面的差异,并提供了跨平台协作的实用技巧,帮助开发者根据项目需求选择合适的仿真工具。

flink9streamer的博客 900

基于大疆TSDK与Pix4D的热红外数据工程化处理:从RJPG到温度正射影像的完整工作流

本文详细介绍了基于大疆TSDK与Pix4D的热红外数据工程化处理完整工作流。通过Python脚本自动化解析RJPG格式的热红外图像,提取并转换其中的原始辐射数据为包含真实温度信息的TIFF文件,再结合Pix4Dmapper进行批量拼接,最终生成可直接用于GIS分析的温度正射影像图。该流程解决了手动处理效率低下、参数校准复杂等难题,实现了从原始数据到定量分析成果的高效、准确、可重复生产。

weixin_29161785的博客 377

C++ mpg(要自己备一个)输出frame失败

// SDL_Demo1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include<output> extern "C" { #include<libavcodec/avcodec.h> } using namespace xiuye; #define INBUF_SIZE 4096 static void pgm_save(unsigned char* buf, int wra.

修也 450

电表协议避坑指南:DLT645-2007与Modbus RTU的5大核心差异对比

本文深入对比了DLT645-2007与Modbus RTU两大电表通讯协议的核心差异,涵盖协议定位、数据地址、报文结构及实测性能。DLT645-2007作为电力行业标准,数据定义统一但效率受限;Modbus RTU作为通用协议,灵活高效但需依赖厂家点表。文章结合实测数据与开发经验,为不同场景下的协议选型与编程实践提供了清晰的避坑指南。

weixin_29166013的博客 108

完美解决#define _AFXDLL or do not use /MD[d]

这个问题经常出现在尝试使用Visual Studio 较高版本(2008,2010)编辑较低版本(Visual C++ 6.0)时使用“在静态库中使用MFC”的情况。在·在网上查找方法,无非是“改成在共享DLL中使用MFC”,或者将#include 改成等方法。笔者未尝试过第二种方法,但是第一种倒是确实好用。第二种不推荐,因为如果使用了afx.h中的函数和变量,atlstr.h没有怎么办?

喻大帅的软件工作室 2万+

vLLM 显存泄漏与 OOM 深度排查:从日志到火焰图

系统性地排查 vLLM 运行中的显存泄漏和 OOM 问题,包括 CUDA 内存快照、PyTorch 内存分析器、火焰图工具。

kaixin110a的博客 187

Claude Code 从入门到精通,通过实战项目穿插 Agent Skills、MCP、Hooks、子代理、插件等十五个知识点

本文介绍了Claude Code的高级使用技巧,通过一个个人简历网站实战项目,详细讲解了15个核心知识点。主要内容包括:三种权限模式(默认/编辑/计划)的使用与切换;历史会话管理(/resume、/rename、/clear命令);会话回滚功能(/rewind);以及危险参数--dangerously-skip-permissions的注意事项。文章还演示了如何通过计划模式拆分代码文件,并强调了在复杂任务中仔细检查规划步骤的重要性。这些技巧能帮助开发者更高效地使用Claude Code完成项目开发。

1788

fatal error C1020:意外的#endif,意外的#else,LF/CRLF问题,与异常的编译错误

在正常的代码的情况下,出现上述的错误或者是奇怪的错误,或者是不应该报错的地方,基本上都可以认为是文件编码/换行符的问题

大全麦的博客 2024

【RT-DETR有效改进】手把手带你调参RT-DETR,1:1复现官方版本实验环境

本文是带大家进行调参,利用ultralytics仓库1:1复现RT-DETR官方实验环境,从而在后期发表论文 的时候省去一些不必要的麻烦,例如被审稿人提出质疑,本文的调参内容均有依据,根据RT-DETR官方Github上发布的版本进行设置本文的调参以ResNet18为例,其余的何其的调参基本一致。RT-DETR剑指论文专栏,持续复现各种顶会内容——论文收割机RT-DETR。

Snu77的博客 9938

VS2008中"fatal error C1083:无法打开包括文件:“Stdafx.h”: No such file or directory”

错误类型1: 环境:VS2008 语言:C++      下午出了一个非常可恶的问题,我的一个基于MFC 对话框的程序因为预编译头文件stdafx.h的原因始终无法编译通过。 由于程序整体是需要预编译头文件的。因此工程内所有cpp文件通通都包括了#include stdafx.h。      我自己写的文件放在工程文件夹下自建的一个文件夹里。比如工程名DynamicPathPlan

skiing_886的专栏 6万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C++ 中stdafx.h是什么意思

Standard Application Fram Extend 没有函数库,只是定义了一些环境参数,使得编译出来的程序能在32位的操作系统环境下运行。 Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编译程序也要花费相当长的时间来完成工作。由于每个.CPP文件都包含相同的include文件,为每个.CPP文件都重复处理这些文件就显得很傻了。 为避免这种浪费,Ap

蹒跚学步 1243

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

笔记:Visual Studio中头文件stdafx.h的作用(含解决方法:错误:C2653 不是类或命名空间名称)

,与项目的源代码文件存放在同一个文件文件夹下,通过#include"stdafx.h"引用;从内容上来说,头文件stdafx.h中可以包含。

wu_zhiyuan的博客 4683

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

_AFXDLL

经常发现有#ifdef _AFXDLL.......#else......这样的语句我也在网上找了找答案,得知:定义这个符号表示动态连接MFC。 在用VC编程时,1新建-》2MFC APPWIZARD-》3....-》4...-》到 STEP 3 OF 4这一步有个选项 1

4006

C1020: 意外的 #endif

对于“ fatal error C1020: 意外的 #endif ”错误,原因大致如下:   如果使用了预编译头,VC会在所有CPP文件里寻找 #include   "stdafx.h " 在找到这行代码之前,VC会忽略所有代码。 也就是说,下例中,VC 找到第二行 #include "stdafx.h" 之前,会将第一行#ifndef _EiC 忽略掉,因此出现“意外的 #end

dasgk的专栏 6301

anaconda ERROR REPORT

安装anaconda的坑 在安装anaconda3时,虽然表面上安装好了,但是打开anaconda prompt会报ERROR REPORT ![QQ截图20211018152623](C:\Users\86156\Desktop\QQ截图20211018152623.png) (base) C:\Users\wei>conda activate tensoflow1 (tensoflow1) C:\Users\wei>conda install seaborn Collecting pac

qq_51169864的博客 2619

_USRDLL和_AFXDLL的用法

参考案例:http://coolerbaosi.iteye.com/blog/1779525  (推荐博客:http://coolerbaosi.iteye.com/ ) 参考文档:http://computer-programming-forum.com/82-mfc/d277aca893dd77cb.htm 参考文章:http://blog.csdn.net/honker110/artic

春夜喜雨的专栏 5401

_AFXDLL AFX_EXT_CLASS

Visual C++  使用 AFX_EXT_CLASS 导出和导入  扩展 DLL 使用 AFX_EXT_CLASS 宏导出类;链接到扩展 DLL 的可执行文件使用该宏导入类。用于生成扩展 DLL 的相同头文件可通过 AFX_EXT_CLASS 宏与链接到 DLL 的可执行文件一起使用。 在 DLL 的头文件中,将 AFX_EXT_CLASS 关键字添加到类的声明中,如下所示:

kevin的专栏 655

_USRDLL _AFXDLL _WINDLL 三种dll编译宏的具体含义

常见的编译参数VC建立项目时总会定义"Win32"。控制台程序会定义"_CONSOLE",否则会定义"_WINDOWS"。Debug版定义"_DEBUG",Release版定义"NDEBUG"   与MFC DLL有关的编译常数包括:   _WINDLL 表示要做一个用到MFC的DLL   _USRDLL 表示做一个用户DLL(相对MFC扩展DLL而言,静态)   _AFXDLL 表示使用MFC动...

迪迦 • 奥特曼 1160

Cmake在windows支持预编译头文件(stdafx.h)

      最近一直在研究cmake构建项目,之前接触cmake的时候就感觉不太喜欢cmake,觉得它太乱了,产生了太多的中间文件,产生的项目文件也不是特别友好,在windows下,生成的项目文件经常需要修改,而在linux和常规的makefile风格也打不一致,文件太多,不方便学习研究。       不够经过这段时间系统的研究,觉得cmake还是非常强大的,吃透之后它的确非常方便,比手工写ma...

帘卷西风的专栏 7047

vs2019 #define_AFXDLL or do not use/MD[d]

如果是Debug的“在静态库中使用MFC”,不要使用MDd,改用MTd,然后编译即可通过。如果是Debug的“在共享DLL中使用MFC”,注意不要使用MTd,改用MDd;如果是Release版本的“在共享DLL中使用MFC”,不要使用MT,使用MD。如果是Release版本“在静态库中使用MFC”,不要使用MD,使用MT;解决方案:项目属性(Alt+F7)——C/C++——代码生成——

victory_xhnh的博客 267

R中执行if else报错:unexpected 'else' in "else"

注意if else的结构写法,有以下三种,除此之外,会不识别else。 结构1 :     if()xxelse yy # 一行;结构2:     if(){xx} else{yy}   或者      if(){   xx }e...

weixin_34025051的博客 7909

_USRDLL _AFXDLL _WINDLL _AFXEXT等宏控制的三种dll编译宏的具体含义

1 DLL分类:

nsaygl的专栏 3249
上一篇: redhat6.4配置yum
下一篇: fatal error C1859: 意外的预编译头错误
Maybe______
博客等级 码龄10年 26粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值