软件工程师,不了解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

相关文章
|
缓存 NoSQL 算法
Redis(十三)-Redis的配置文件详解
本文将详细介绍Redis的配置文件。redis.conf 文件是Redis中最重要的一个文件,其属性配置会直接影响到Redis。本文主要介绍一些常用的配置。后面的文章会详细介绍某些重点配置。
432 0
|
9月前
|
机器学习/深度学习 人工智能 缓存
每个人都可以成为虚拟主播,一键创建属于你的虚拟形象,RAIN 为你实时生成逼真动画角色
RAIN 是一款创新的实时动画生成工具,支持在消费级硬件上实现无限视频流的实时动画化,适用于直播、虚拟角色生成等场景。
343 25
每个人都可以成为虚拟主播,一键创建属于你的虚拟形象,RAIN 为你实时生成逼真动画角色
|
消息中间件 运维 安全
云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维
在 2024 年云栖大会上,阿里云智能集团产品专家刘尧全面介绍了云消息队列 ApsaraMQ Serverless 的落地成果和产品进展。此外,我们还邀请到杭州优行科技有限公司中间件消息研发负责人王智洋,分享了 ApsaraMQ for Kafka Serverless 助力曹操出行实现成本优化和效率提升的实践经验。
469 113
|
10月前
|
SQL 关系型数据库 MySQL
MySQL操作利器大公开!这几款客户端让你事半功倍
本文介绍了多种MySQL数据库管理工具,包括命令行工具、图形化用户界面(GUI)工具和Web界面工具。主要工具有: 1. **Navicat for MySQL**:功能强大,支持多种数据库管理任务,但需付费。 2. **DBeaver**:开源免费,支持多种数据库,安装包较大。 3. **MySQL Workbench**:官方提供的图形化工具,适合MySQL全家桶用户。 4. **HeidiSQL**:轻量级Windows客户端,简单易用。 5. **phpMyAdmin**:基于Web的管理工具,易于部署和使用。 6. **SQLyog**:适用于Windows,功能丰富,有免费
1280 3
|
负载均衡 算法 容灾
slb基础概念
【9月更文挑战第2天】
3707 25
|
数据可视化 数据挖掘 数据库
低代码开发全解析核心功能及其优势
低代码开发平台采用图形界面与预构建组件加速软件开发,降低技术门槛与成本,并支持敏捷迭代与快速部署。其核心功能包括可视化建模、预构建组件库、业务流程自动化、集成与连接性、多平台应用开发、数据分析报告、版本控制与协作、测试调试工具、安全性与合规性及快速部署更新。优点体现在提升开发速度与效率、降低成本、加强团队合作及提高灵活性与可扩展性。选择平台时需明确需求、评估功能与灵活性、考虑易用性、集成能力、安全性与合规性及成本与定价模型。例如,Zoho Creator作为成熟平台,拥有丰富的经验和广泛的应用案例。低代码开发已成为企业数字化转型的关键工具。
332 13
|
算法 测试技术 数据处理
实时目标检测神器:YOLOv5的安装与使用详解
实时目标检测神器:YOLOv5的安装与使用详解
636 1
|
前端开发 JavaScript Java
计算Java项目|基于SpringBoot的协力服装厂服装生产管理系统的设计与实现
计算Java项目|基于SpringBoot的协力服装厂服装生产管理系统的设计与实现
167 0
|
API 网络安全 数据安全/隐私保护
SMTP邮件邮箱API发送邮件的方法和步骤
使用SMTP邮件邮箱API(如AokSend)发送邮件涉及6个步骤:获取SMTP服务器地址和端口,进行身份验证,构建邮件内容,连接到服务器,发送邮件及处理结果。例如,Gmail的SMTP服务器地址是smtp.gmail.com,端口587。此方法适用于程序化发送邮件,确保安全并支持大规模发信服务。
|
Kubernetes API 数据库
容器服务 Pod 处于 CrashLoopBackOff的原因及解决方法
"CrashLoopBackOff" 是 Kubernetes 中 Pod 进入的一种错误状态,通常是由于容器不断崩溃(失败)而触发的重启策略所导致的。以下是 Pod 处于 CrashLoopBackOff 状态的原因及相应的解决方法: ### 原因: 1. **应用错误:** - 容器内部的应用程序崩溃,导致容器退出。 - 应用程序可能因为异常、未捕获的错误、配置问题、依赖缺失等原因导致崩溃。 2. **错误的启动命令:** - Pod 的启动命令或入口点设置错误,导致容器无法正确启动。 3. **资源限制:** - Pod 可能受到内存或 CPU 资源限制,
3962 0