软件工程师,不了解64位程序开发你就out了

简介: 软件工程师,不了解64位程序开发你就out了

概述

□ 64位Windows系统下也能运行32位程序,是因为有一个WOW64子系统。它能将32位应用程序的API调用转换成对原生64位系统的调用。正是因为WOW64的存在,32位应用程序在64位系统下并不能发挥最佳的性能,反而比在32位系统下有大约2%的性能损失。如果开发的是64位应用程序,则不需要依赖WOW64运行,并可带来大约5%-15%的性能提升(5%-10%由于采用了64位架构,1%-5%由于未使用WOW64)。

□ 32位程序的最大地址空间是4GB,64位程序的最大地址空间是可以大于4GB的。

□ 64位程序不再区分cdecl、stdcall等各种调用方式。gcc在64位下面,不再支持__attribute((cdecl))__和__attribute((stdcall))__。

□ 64位程序不再使用ESP,而是使用增加的几个64位寄存器,因为ESP不支持64位空间的栈。

□ 虽然在64位Windows系统下可以运行64位和32位进程,但是64位代码和32位代码不能在相同进程上运行。你的代码要么全部是64位,要么全部是32位,要加载的库和组件也要满足这一要求。

数据类型字节长度

32位程序和64位程序,其数据类型的字节长度并不完全一致,可参看下表。

image.png

注意事项1

□ 使用“_WIN32”宏(不要用“WIN32”宏)来判断是不是Windows平台编译环境,使用“_WIN64”宏来区分编译环境是32位还是64位。

image.png

注意事项2

□ 64位整型数据在Windows和Linux中的输出格式不一样。

Windows下,可参考下面的示例代码。

__int64 a;
printf("%I64d", a);
unsigned __int64 b;
printf("%I64u", b);
printf("%Iu", c);

Linux下,可参考下面的示例代码。

long long a;
printf("%lld",a);
unsigned long long b;
printf("%llu", b);
size_t c;
printf("%zu", c);

注意事项3

□ 谨慎使用printf、scanf等类似函数。

1、64位程序时,size_t与%u不匹配。下面的代码是不合理的。

const char *invalidFormat = "%u";
size_t value = SIZE_MAX;
printf(invalidFormat, value);

2、64位程序时,指针为8个字节,转化为字符串需要16个字节,内存会溢出。下面的代码是不合理的。

char buf[9];
const char *pointer = "hello";
sprintf(buf, "%p", pointer);

 

注意事项4

□ 避免使用类似下面的魔法数字,尽量使用sizeof,或者<limits.h>、<inttypes.h>中定义的值。

image.png

以下为一些错误使用魔法数字的示例。

size_t ArraySize = N * 4;
intptr_t *Array = (intptr_t *)malloc(ArraySize);

size_t values[ARRAY_SIZE];
memset(values, 0, ARRAY_SIZE * 4);

size_t n, r;
n = n >> (32 - r);

hFileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE,  
    (DWORD) 0, (DWORD)(szBufIm), (LPCTSTR)&FileShareNameMap[0]);

正确的示例可参看下面的代码。

size_t ArraySize = N * sizeof(intptr_t);
intptr_t *Array = (intptr_t *)malloc(ArraySize);

size_t values[ARRAY_SIZE];
memset(values, 0, ARRAY_SIZE * sizeof(size_t));
// 或者
memset(values, 0, sizeof(values));

size_t n, r;
n = n >> (CHAR_BIT * sizeof(n) - r); 

hFileMapping = CreateFileMapping((HANDLE)(LONG_PTR)-1, NULL, PAGE_READWRITE,  
    (DWORD) 0, (DWORD)(szBufIm), (LPCTSTR)&FileShareNameMap[0]);

另外,可以通过下面的代码很清楚地看到,-1与魔法数字0xFFFFFFFF在64位程序下的输出值不一样。

#include <iostream>
using namespace std;

void foo(void *ptr)
{
    cout << ptr << endl;
}

int main()
{
    cout << "-1\t\t";
    foo((void *)-1);

    cout << "0xFFFFFFFF\t";
    foo((void *)0xFFFFFFFF);
    
    return 0;
}

image.png

注意事项5

□ 不要在整型和指针/句柄间进行转换。如果确实需要转换,请使用intptr_t或uintptr_t。intptr_t和uintptr_t是为了跨平台,其长度总是所在平台的位数,所以用来存放地址。

以下为一些错误的示例。

image.png

image.png

image.png

image.png

image.png

image.png

相关文章
|
7月前
|
小程序 前端开发 测试技术
小程序开发心得体会
小程序开发心得体会
|
2月前
|
前端开发 JavaScript Java
一个软件开发工程师需要学几种编程语言?为什么?
一个软件开发工程师需要学几种编程语言?为什么?
224 64
|
3月前
|
存储 XML API
安卓应用程序开发:从新手到专家的旅程
【8月更文挑战第33天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索如何从一个对安卓应用程序开发一无所知的新手,成长为一个能够独立开发复杂应用程序的专家。我们将通过实际案例和代码示例,深入理解安卓开发的各个方面,包括用户界面设计、数据存储、网络通信等。无论你是刚刚入门,还是已经有一些基础,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上更进一步。
|
3月前
|
小程序 前端开发 JavaScript
Java开发工程师转小程序开发的前景如何?
Java开发工程师转小程序开发的前景如何?
51 0
|
7月前
|
Java API 开发工具
安卓应用程序开发:从新手到专家
【2月更文挑战第28天】 在这篇文章中,我们将探索安卓应用程序开发的过程,从基本概念到高级技术。我们将讨论如何设置开发环境,创建你的第一个安卓应用,理解安卓的生命周期,以及如何使用各种API和库来增强你的应用。无论你是刚刚入门的新手,还是希望提升技能的开发者,这篇文章都将为你提供有价值的信息。
|
7月前
|
算法 Linux C语言
嵌入式软件开发学习路线精心总结
嵌入式软件开发学习路线精心总结
142 0
|
XML Java 数据库
[总结]安卓开发工程师之路
[总结]安卓开发工程师之路
103 0
开发经验
首先最重要的就是每天早上打开项目之前,先 pull 一次最新的代码
73 0
|
程序员
你可能没发现你只是程序员不是工程师
你可能没发现你只是程序员不是工程师
107 0
你可能没发现你只是程序员不是工程师