64位配置和编译

第四讲 创建64位的配置

 

编译器

首先,你要确定你所使用的Visual Studio的版本允许你编译程序为64位代码。如果你想使用最新的版本(写本课本时)Visual Studio 2008 来开发64位应用,以下的表格帮助你理解你所需要的Visual Studio 版本。

                       

     表1 不同版本的VS2008的能力

 

如果你使用的VS的版本使你可以去创建64位代码,你需要检查是否安装了64位的编译器, 图1显示在安装VS2008时,64位编译器没有被选中。

 

    图1 安装VS2008时64位编译器没有被勾选

创建64位的配置

在VS2005/2008中创建一个64位应用是一个非常简单的过程。困难会出现在之后编译新的程序和检查错误的时候。创建一个64位程序,你需要做以下的步骤。

第一步

打开Configuration Manager


第二步

在Configuration Manager 中选择new platform

 

第三步

选择64位平台,选择32位的配置作为基础,VS会自动修改那些会影响到编译模式的配置

 

第四步

你已经添加了新的配置,现在可以选择64位的配置,然后开始编译了。

 

修改参数

如果你幸运的话,你不需要修改64位程序。但这个是取决于你的代码,它的复杂性,以及它所用的库的数量。你现在需要马上修改的值应该是堆栈的大小(stack size),如果你的程序所用的是堆栈的默认值,即 1 Mbyte,64位版本的时候,应该改为2 Mbyte。你不是必须要这么做,但是提前这样做可以更保险。如果你用的是其他值,你需要保证64位使用的数值是之前数值的两倍。你可以通过改变project setting 中的Stack Reserve Size 和Stack Commit Size值来实现以上所说的变化。

 

下一步?

有一个64位的配置,不代表你的编译能够成功或者是能运行。 下一讲,我们会介绍编译过程,以及怎样发现隐藏的问题。

 

第五讲 编译64位应用    

我们需要向读者说明,我们不可能涵盖编译一个64位应用的所有细节问题。每个项目有自己的特有的设定,所以你需要特别注意这些设定。本讲只会涵盖对任何程序都重要的步骤,这些步骤只是一个开始,更多的问题需要读者自己去解决。

当你尝试编译一个你产品的64位版本时,首先确认所有必须的64位的库已经成功安装了,而且它们的路径是正确的。例如32位与64位的以“lib”结尾的库文件是不同的,而且在不同的目录中,如果有bug请修改。

注意:如果库是以源代码的形式存在的,那么会存在库项目的64位的配置。 注意到,当你修改一个源代码的配置,以编译适合你的64位版本时,你存在可能侵犯了版权的可能性,请谨慎。

汇编器

Visual C++ 不支持64位的内联汇编(inline assembler),你可以选择一个外部的64位汇编器(如,MASM)或者是重写这些汇编语言。

编译错误和警告的实例

当开始编译你的程序时,你会碰到许多因为显式类型转换 和隐式类型转换所带来的问题(explicit and implicit type conversions)。以下是一个例子。

这段代码在32位上成功编译,但在64位上不行,Visual C++ 会产生如下warning

因为函数strlen()返回的类型是size_t,在32位系统上,类型size_t与unsigned int的类型一致,所以编译器选择"void foo(unsigned int)"来调用。但在64位的模式下,size_t与unsigned int的类型不一致。 size_t 变成了64位,但unsigned int类型仍然保持了32位。因而编译器不知道哪一个foo()函数来调用。

现在来考虑一段由Visual C++编译64位代码时,所产生的错误:

GetSize()函数返回的类型是 INT_PTR,在32位时,与int类型一致。在64位时,INT_PTR是64位而隐式的转换为32位。因为可能会导致高位值丢失,这就是系统给出警告的原因。 当数组中元素数量超过了INT_MAX, 一个隐式类型转换就有可能会导致错误。去除这个警告和可能错误的方式就是,你应该将len的类型写为INT_PTR 或者是ptrdiff_t 类型。

在你已经完全了解了64位错误的规律前,都不要去隐藏warning。你有可能会隐藏一个错误,使得之后更难发现它。你可以在之后的课程中,学到更多的关于64位错误的规律和发现他们的方式。你可以同样参考一下文章  "20 issues of porting C++ code on the 64-bit platform", "A 64-bit horse that can count"。

size_t 和ptrdiff_t 类型

在大多数关于数据不兼容的编译错误和警告中,我们应该尤其考虑两种类型 size_t 和ptrdiff_t, 这两者在编译64位代码中最容易出现问题。如果你使用的是Visual C++编译器,这些类型可能被整合到编译器中,你不需要增加库描述文件。但是如果你使用的是GCC, 你可能需要添加头文件“stddef.h”。

size_t 是一个C/C++ 基本unsigned integer类型。 它是sizeof 操作的返回值。这种类型的大小之所以这样选择,是因为它可以用来存储理论上的最大数组的大度值。例如,size_t在32位系统上是32位,在64位系统上是64位。换句话说,你可以安全的用size_t 类型的变量存储一个指针,但是不包括指向函数的指针。这个类型经常作为在循环中的计数器的类型,作为数组索引,用来存储长度,或者用于地址的计算中。以下的这些类型与size_t类似:SIZE_T, DWORD_PTR, WPARAM, ULONG_PTR。 虽然你可以在size_t中存储一个指针,但是最好使用另外一个unsigned integer 类型uintptr_t ——它的名字就反映了它的用途。size_t与uintptr_t 是同义的。

ptrdiff_t是一个C/C++ 基本signed integer类型。这种类型的大小之所以这样选择,是因为它可以用来存储理论上的最大数组的大度值。例如,ptrdiff _t在32位系统上是32位,在64位系统上是64位。与size_t类似,你可以安全的用ptrdiff _t 类型的变量存储一个指针,但是不包括指向函数的指针。ptrdiff_t类型也是表达式"ptr1-ptr2"的返回值。这个类型经常作为在循环中的计数器的类型,作为数组索引,用来存储长度,或者用于地址的计算中。与它类似的是SSIZE_T, LPARAM, INT_PTR, LONG_PTR。 与它同义的是intptr_t,intptr_t可以用来存储一个指针。

size_t 和ptrdiff_t被创造就是为保证地址运算的正确性。在较长的时间内,int的类型都与机器字(machine word)的长度一致,因而int类型变量经常被作为数组索引,或者是用来存储物体和指针大小。因而地址运算也是通过int和unsigned类型来编译的。int类型在大多数的C/C++教程中出现在循环体做作为索引。下面是一个经典的例子:

当处理器不断的发展,继续扩展int的长度显得不那么合理了。这是由许多因素造成的如:节约使用的内存,最大的兼容性等。因而,许多的数据模式出现,来描述基本C与C++类型之间的关系。所以现在选择一个类型来存储指针和物体大小就不那么容易了。size_t 和ptrdiff_t类型的出现就成了最好的解决方案。它们肯定可以在地址运算中使用。现在如下的代码将成为经典:

这段代码才是能提供最好的安全性,移植性和高性能的代码。在之后的课程中你将学到原因。

size_t 和ptrdiff_t类型可以被称为memsize类型。Memsize 的出现是为了简单的描述所有能作为存储最大数组的长度值,和作为这样数组的索引的值 的类型。当说到memsize类型时,你需要能立刻想到它们在32位系统上是32位的,在64位系统上是64位的。以下是一些memsize类型:size_t, ptrdiff_t, pointers, SIZE_T, LPARAM。

posted @ 2013-11-11 20:54  宇月--测试开发梦想家  阅读(538)  评论(0编辑  收藏  举报