Visual Studio中的“Any CPU”目标是什么意思?

577

我对Visual Studio 2008中.NET平台的构建选项感到困惑。

"Any CPU"编译目标是什么,它生成什么样的文件?我检查了这个“Any CPU”版本的输出可执行文件,并发现它们是x86可执行文件(谁不会看出来呢!)。那么,将可执行文件定位到x86与“Any CPU”有什么区别吗?

我还注意到另一件事,那就是托管C++项目没有这个平台选项。为什么会这样?这是否意味着我对“Any CPU”可执行文件是32位纯净版的怀疑是正确的?


4
在决定使用哪个平台目标时,还有一件事需要考虑:如果启动项目的目标是“任何 CPU”,且您正在运行 64 位操作系统,则在调试时将失去编辑并继续的功能(您实际上正在调试一个 64 位进程)。您可以将启动项目的目标设置为 x86 来解决这个问题。(从启动项目引用的程序集可能仍然针对 Any CPU 进行目标设置。) - Cristian Diaconescu
10
@CristiDiaconescu,使用VS2013,现在可以进行编辑和继续操作。 - ms007
2
我认为这里应该有一些注释,说明项目是应用程序还是类库,因为针对后者设置目标位数可能会影响其在平台上对消费应用程序的可用性。我曾经遇到过这种情况,使用 x86 库被 AnyCPU 应用程序消费时,我不得不设置 Prefer 32-bit 以避免加载错误。 - SteveCinq
8个回答

431

AnyCPU组件将在加载到64位进程时JIT为64位代码,而在加载到32位进程时则为32位。

通过限制CPU,您会说:“该组件正在使用某些(可能是未管理的)东西,需要32位或64位。”


3
那么,我应该如何在C++中生成能够即时编译成x64的汇编代码? - galets
58
C++ 项目编译成本地代码,因此 JIT 编译器没有参与... 因此,你无法做你所要求的事情。 - cplotts
7
这个答案不再正确。AnyCPU 的意义在多年间已经发生多次变化。 - P.Brian.Mackey
2
@P.Brian.Mackey 公平地说,这仍然是官方文档中所记录的内容:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/platform-compiler-option - kayleeFrye_onDeck
1
作为32位或64位dll的常见例子,Oracle.DataAccess锁定了选择其中之一。 - beanmf
显示剩余2条评论

344

我认为大部分重要内容已经被讨论了,但我想补充一点:如果你编译成 Any CPU 并在 x64 平台上运行,则无法加载 32 位 DLL 文件,因为你的应用程序没有在 WoW64 中启动,而这些 DLL 文件需要在那里运行。

如果你编译为 x86,则 x64 系统将在 WoW64 中运行你的应用程序,你就可以加载 32 位 DLL 文件。

所以我认为如果你的依赖项可以在任何环境中运行,那么你应该选择 "Any CPU",但如果你有 32 位依赖项,则应该选择 x86。 这篇来自微软的文章对此进行了解释:

/CLRIMAGETYPE (Specify Type of CLR Image)

顺便说一句,这份其他的微软文档也同意 x86 通常是更具可移植性的选择:

由于几乎可以在任何设备上运行,因此选择 x86 通常是应用程序包的最安全配置。在某些设备上,使用 x86 配置的应用程序包无法运行,例如 Xbox 或某些 IoT Core 设备。但是,对于 PC,x86 包是最安全的选择,并且具有最大的设备部署范围。相当一部分 Windows 10 设备继续运行 Windows 的 x86 版本。


3
也许您可以编辑您的回答,说明如何确定给定的DLL是否仅为32位。据我所知,这个链接可以解决这个问题。我认为我们希望的是既是“Any CPU”又是x86的DLL。 - Dan W
1
+1 是一个重要的区别。在使用一个32位依赖项时(没有被识别为这样),我无法解决那些晦涩难懂的运行时错误信息。凭直觉改变了CPU目标后,它就可以工作了,但还是去寻找“原因”。总有一天当所有东西都是64位时,不兼容性问题会像16位与32位现在一样显得古怪。 - Gerald Davis
4
@GeraldDavis - 我同意。具有讽刺意味的是,没有技术上的障碍使得无法混合32位和64位的依赖项(只是CLR中缺少了一个thunking层),早期的.NET时代我对需要考虑比特数进行部署感到失望(考虑到这是一个VM/JIT,本来可以提供更多的附加值)。 - codenheim
2
@mrjoltcola:更糟糕的是,微软决定将注册表项分为32位和64位宇宙,即使它们控制屏幕颜色、默认设置等等,我无法理解这样做的原因。 - supercat
@GeraldDavis 在引入128位之前,可能会有一个短暂的时间,一切都将是64位。到那时,每个人都会失望地发现他们喜爱的32位应用程序无法运行。(我还记得Windows从16位到32位的转换...) - Derek Johnson
显示剩余3条评论

94

10
这是截至2018年9月6日和VS 15.8.0版本为止最准确的答案。 - Raikol Amaro

53

这里是一个快速概述,解释了不同的构建目标。

从我的经验来看,如果你想要构建一个可以在x86和x64平台上运行的项目,并且没有任何特定的x64优化,我建议将构建更改为明确指定"x86"。

原因是有时你可能会得到一些DLL文件冲突或者一些代码在x64环境中崩溃WoW。通过明确指定x86,x64操作系统将把应用程序视为纯x86应用程序,并确保一切顺利运行。


44
如果你在为服务器环境编写应用程序并希望其能够使用超过2GB的内存,这可能是可怕的。同时,你也将放弃任何未来可能出现的x64 JIT优化。 - Austin Harris
我在使用AnyCPU编译选项时遇到的运行时问题数量已经足以让我停止使用它,除非有人明确要求能够在两者上都可以工作的二进制文件。在过去的十年中,我没有收到任何人要求使用x86二进制文件而不是x64的要求。 - kayleeFrye_onDeck
4
抱歉,我不同意。指定x86后,x64操作系统仍会在WOW64中运行您的x86应用程序,以确保一切顺利运行。 - Mandeep Janjua
2
这只是对那些不完全理解其影响的人的错误建议。@AustinHarris给出了一个很好的例子。想象一下一个被限制在几GB RAM的Web工作进程(我最近在生产中处理过这个问题)。 - rgoliveira

51

请查看文章Visual Studio .NET 平台目标解释

默认设置为“Any CPU”,意味着程序集将在当前运行的CPU上本地运行。也就是说,它将在64位机器上作为64位运行,在32位机器上作为32位运行。如果程序集是从64位应用程序中调用的,则会作为64位程序集执行,以此类推。

上面的链接已经报告失效,这里提供另一篇类似的文章:.NET 4.5和Visual Studio 11下 AnyCPU 的真正含义


43

"Any CPU" 表示当程序启动时,.NET Framework会根据操作系统的位数来确定是否以32位或64位运行你的程序。

x86Any CPU 之间有区别:在x64系统上,编译为X86的可执行文件将作为32位可执行文件运行。

关于你的怀疑,只需要在Visual Studio 2008命令行中运行以下命令。

dumpbin YourProgram.exe /headers

它将告诉您程序的位数,以及更多的信息。


9
如果使用“任意 CPU”构建,dumpbin标题中会显示32位。 - Kirbinator

38

Any CPU表示它可以在任何平台上运行。这是因为托管代码类似于Java。将其编译为字节码,由.NET框架在运行时解释。

C++没有此选项,因为它被编译为特定于平台的机器代码。


13
+1 对于回答其他人没有回答的问题(关于C++项目没有AnyCPU选项) - cplotts
1
C++/CLI可以编译为IL代码而不需要任何机器码(/clr:pure)。但在C++中,sizeof(void*)仍然需要是一个编译时常量;因此,即使没有涉及机器码,你仍然不能创建一个能够同时在32位和64位上运行的二进制文件。 - Daniel

7

我建议阅读此篇文章

使用AnyCPU时,其语义如下:

  • 如果进程运行在32位的Windows系统上,则它将作为32位进程运行。CIL被编译成x86机器码。
  • 如果进程运行在64位的Windows系统上,则它将作为32位进程运行。CIL被编译成x86机器码。
  • 如果进程运行在ARM Windows系统上,则它将作为32位进程运行。CIL被编译成ARM机器码。

11
仅当选择“优先使用32位”时才会生效。 - Florian Winter
1
自Visual Studio 11以来,哪个是默认值? - Moerwald
@Moerwald 我相信这是一个已经修复的错误。如果你阅读 mamczas 引用的文章,作者写道:“在当前的 Visual Studio UI 中,“Prefer 32-bit”是灰色和未选中的,但实际上它是启用的...”;在我的 VS 版本(15.8.0)中,该选项仍然是灰色和未选中的,但是它按预期工作(编译后程序集的 CorFlags 部分的标志为 32BITPREF = FALSE)。 - Raikol Amaro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接