
O artigo descreve os principais passos que devem ser seguidos para transferir programas de 32 bits para 64 bits. São descritos os principais problemas enfrentados pelos desenvolvedores que planejam migrar programas de 32 bits para sistemas de 64 bits. É claro que a lista de questões consideradas não está completa, mas esperamos fornecer uma versão mais detalhada deste artigo no futuro.
Transferir programas de 32 bits para 64 bits
Estas são as etapas para migrar aplicativos com sucesso de Windows de sistemas Windows de 32 bits para 64 bits:
Etapa 1: o modo de 64 bits pode ser diferente. Vamos consertar isso
No contexto de uma arquitetura de computador, o termo "64 bits" refere-se a números inteiros de 64 bits e outros tipos de dados deste tamanho. Sistemas de “64 bits” podem significar arquiteturas de microprocessador de 64 bits (por exemplo, EM64T, IA-64) ou arquiteturas de sistema operacional de 64 bits (por exemplo, Windows XP Professional x64 Edition).
AMD64 (ou x86-64, Intel 64, EM64T, x64) é uma arquitetura de microprocessador de 64 bits e conjunto de instruções correspondente desenvolvido pela empresa AMD. Este conjunto de instruções foi licenciado pela empresa Intel sob o nome EM64T (Intel64). A arquitetura AMD64 é uma extensão da arquitetura x86 com total compatibilidade retroativa.
A arquitetura se difundiu como base para computadores pessoais e estações de trabalho. IA-64 é uma arquitetura de microprocessador de 64 bits desenvolvida em conjunto pelas empresas Intel e Hewlett Packard. É implementado nos microprocessadores Itanium e Itanium 2. A arquitetura é usada principalmente em servidores multiprocessadores e sistemas de cluster.
Talvez você esteja interessado: Como baixar dispositivo PCI para Windows 7 de 64 bits
AMD64 e IA-64 são duas arquiteturas diferentes de 64 bits, que são incompatíveis entre si. É por isso que os desenvolvedores devem decidir imediatamente se precisam oferecer suporte a ambas as arquiteturas ou apenas a uma. Na maioria dos casos, se você não desenvolver software altamente personalizado para sistemas de cluster ou não implementar seu próprio DBMS de alto desempenho, provavelmente terá que implementar suporte apenas para a arquitetura AMD64, que é muito mais popular do que IA. -64.
Trata-se especialmente de software para o mercado de PCs, que é quase 100% ocupado pela arquitetura AMD64. Mais adiante no artigo falaremos apenas sobre a arquitetura AMD64 (EM64T, x64), por ser a mais atual para desenvolvedores de software aplicativo atualmente. Falando em diferentes arquiteturas, devemos mencionar a noção de “Modelo de Dados”.
Por modelo de dados Entendemos as correlações entre os tamanhos de fonte aceitos no ambiente de desenvolvimento. Pode haver diversas ferramentas de desenvolvimento que aderem a diferentes tipos de dados para um sistema operacional. Mas normalmente só predomina um modelo que corresponde mais ao ambiente de Hardwares e software.
Um exemplo disso é o Windows de 64 bits, cujo modelo de dados original é LLP64. Porém, por motivos de compatibilidade, o Windows de 64 bits oferece suporte à execução de programas de 32 bits que operam no modo de modelo de dados ILP32LL. A Tabela 1 fornece informações sobre os modelos de dados básicos.
O modelo de dados utilizado influencia muito no processo de desenvolvimento de aplicações de 64 bits, uma vez que o tamanho dos dados utilizados no código do programa deve ser levado em consideração.
Etapa 2: Descubra se você precisa da versão de 64 bits do seu produto
Você deve começar a dominar sistemas de 64 bits com a pergunta: “Eu realmente preciso reconstruir meu projeto para um sistema de 64 bits?” Você só responde a essa pergunta depois de pensar cuidadosamente sobre ela. Por um lado, você pode ficar para trás dos seus concorrentes se não oferecer soluções de 64 bits. Por outro lado, você pode perder o tempo desenvolvendo um aplicativo de 64 bits que não proporcionará nenhuma vantagem competitiva. Vamos listar os fatores básicos que ajudarão você a tomar uma decisão.
2.1. Duração do ciclo de vida do aplicativo
Você não deve criar a versão de 64 bits de um aplicativo com ciclo de vida curto. Graças ao subsistema WOW64, aplicativos antigos de 32 bits funcionam muito bem em sistemas Windows de 64 bits, e é por isso que não faz sentido fazer um programa de 64 bits, já que ele não terá suporte em 2 anos.
Além disso, a prática mostra que a migração para versões de 64 bits do Windows foi atrasada e talvez a maioria de seus usuários use apenas a versão de 32 bits da solução do programa no curto prazo.
Se você planeja o desenvolvimento e o suporte de longo prazo de um produto de programa, deverá começar a trabalhar com a versão de 64 bits da sua solução. Você pode fazer isso sem pressa, mas lembre-se de que quanto mais tempo você não tiver uma versão completa de 64 bits, mais dificuldades encontrará para oferecer suporte a este aplicativo instalado em versões de 64 bits do Windows.
2.2. Uso intensivo de recursos de um aplicativo
Recompilar um programa para um sistema de 64 bits permitirá que você use grandes tamanhos de memória principal e também acelerará sua operação em 5 a 15%. Um aumento de 5 a 10% será obtido devido ao uso das capacidades arquitetônicas do processador de 64 bits, por exemplo, um maior número de registros. O restante do aumento de velocidade de 1 a 5% é explicado pela ausência da camada WOW64, que traduz chamadas de API entre aplicativos de 32 bits e um sistema operacional de 64 bits.
Se o seu programa não funciona com grandes volumes de dados (mais de 2 GB) e a velocidade de sua operação não é crucial, o migração para um sistema de 64 bits Não será tão urgente no futuro próximo. A propósito, mesmo aplicativos simples de 32 bits podem obter benefícios ao iniciar em um ambiente de 64 bits.
Você deve saber que um programa criado com a tecla / GRANDE ENDEREÇO: SIM Você pode alocar até 3 GB de memória se o Windows de 32 bits for iniciado com a chave. Este programa de 32 bits executado em um sistema de 64 bits pode alocar quase 4 GB de memória (na prática, cerca de 3,5 GB).
2.3. Desenvolvimento de biblioteca
Se você desenvolver bibliotecas, componentes ou outros elementos com a ajuda de desenvolvedores terceirizados que criam seu próprio software, deverá agir rapidamente ao criar a versão de 64 bits do seu produto. Caso contrário, os clientes interessados em lançar versões de 64 bits terão que procurar soluções alternativas.
Por exemplo, alguns desenvolvedores de segurança de software e hardware responderam lentamente lançando programas de 64 bits, e isso fez com que alguns clientes procurassem outras ferramentas para proteger seus programas.
Uma vantagem adicional de lançar a versão de 64 bits de uma biblioteca é que você pode vendê-lo como um produto separado. Portanto, seus clientes que desejam criar aplicativos de 32 e 64 bits precisarão adquirir 2 licenças diferentes.
2.4. Dependência do seu produto de bibliotecas de terceiros
Antes de planejar o trabalho de criação da versão de 64 bits do seu produto, descubra se versões de bibliotecas e componentes de 64 bits são usadas. Além disso, conheça a política de preços da versão 64 bits de uma biblioteca. Se o suporte não for fornecido, procure antecipadamente soluções alternativas que suportem sistemas de 64 bits.
2.5. Usando aplicativos de 16 bits
Se suas soluções ainda usam unidades de 16 bits, é hora de se livrar delas. Aplicativos de 16 bits em versões de 64 bits do Windows não são suportados. Devemos explicar aqui uma coisa sobre o uso de instaladores de 16 bits. Eles ainda são usados para instalar alguns aplicativos de 32 bits.
Existe um mecanismo especial que substitui alguns dos instaladores de 16 bits mais populares por suas versões mais recentes. Isso pode levar a falsa ideia de que programas de 16 bits ainda funcionam no ambiente de 64 bits. Lembre-se: não é bem assim.
2.6. Montagem de código
Não se esqueça de que o uso de código assembly grande pode aumentar significativamente o custo de criação da versão de 64 bits de um aplicativo. Depois de pensar em todos os fatores listados e pesar todos os prós e contras, decida se você precisa portar seu projeto para sistemas de 64 bits. Se a resposta for sim, podemos ir mais longe.
Etapa 3: kit de ferramentas
Se você decidiu desenvolver a versão de 64 bits do seu produto e está disposto a investir tempo, ainda não é suficiente para garantir o sucesso. A questão é que você deve possuir todo o conjunto de ferramentas necessárias, e aqui poderá enfrentar algumas dificuldades. A ausência de um compilador de 64 bits pode ser o problema mais simples, porém mais intransponível.
Se tudo estiver claro sobre a ausência de um compilador de 64 bits, outros problemas semelhantes podem parecer menos transparentes e ocorrer apenas na fase de portabilidade do projeto para uma nova arquitetura. É por isso que gostaríamos de aconselhá-lo a descobrir com antecedência se existem todos os componentes necessários para implementar a versão de 64 bits do seu produto. Você pode enfrentar surpresas desagradáveis.
Claro que é impossível listar aqui tudo o que você pode precisar para um projeto, mas continuaremos a lista para ajudá-lo a se orientar e talvez lembrar de outras coisas necessárias para implemente seu projeto de 64 bits:
3.1. Um compilador de 64 bits
Quase não há mais a dizer sobre a importância de ter um compilador de 64 bits. Simplesmente deve ser assim. Se você planeja desenvolver aplicativos de 64 bits usando a versão mais recente do Visual Studio, a Tabela 2 a seguir ajudará você a entender qual edição do Visual Studio você precisa.
3.2. Computadores de 64 bits sob controle de um sistema operacional de 64 bits
Naturalmente, você pode usar Máquinas virtuais para iniciar aplicativos de 64 bits em computadores de 32 bits, mas é muito inconveniente e não fornecerá o nível de teste necessário. É desejável que as máquinas tenham pelo menos 4 a 8 GB de memória principal.
3.3. Versões de 64 bits de todas as bibliotecas usadas
Caso as bibliotecas sejam apresentadas em códigos-fonte, deve haver uma configuração de projeto de 64 bits. Pode ser uma tarefa difícil e ingrata atualizar a biblioteca para um sistema de 64 bits por conta própria, e o resultado pode não ser confiável e conter bugs. Além disso, você pode violar contratos de licença com essas ações. Se você usa bibliotecas na forma de unidades binárias, também deve descobrir se existem unidades de 64 bits.
Você não pode usar uma DLL de 32 bits em um aplicativo de 64 bits. Você pode criar um link especial via COM, mas será uma tarefa grande e difícil. Lembre-se também de que talvez você precise gastar algum dinheiro extra para comprar a versão de 64 bits da biblioteca.
3.4. Falta de código assembly integrado
Visual C++ não oferece suporte a um assembler embutido de 64 bits. Você deve usar um assembler externo de 64 bits (por exemplo, MASM) ou ter uma implementação com a mesma funcionalidade em C/C++.
3.5. Atualização da metodologia de teste
Isso significa uma reconstrução considerável da metodologia de testes, atualização de testes unitários e utilização de novas ferramentas. Falaremos sobre isso com mais detalhes posteriormente, mas não se esqueça de levar isso em consideração na fase de avaliação do tempo gasto na migração de uma aplicação para um novo sistema.
3.6. Novos dados para testar
Se você estiver desenvolvendo aplicativos com uso intensivo de recursos usando uma grande quantidade de memória principal, deverá fornecer reabastecimento do banco de dados de entrada de teste. Ao testar a carga de aplicativos de 64 bits, é uma boa ideia exceder os limites de 4 GB de memória usada. Muitos erros podem ocorrer somente nessas condições.
3.7. Sistemas de segurança de 64 bits
O sistema de segurança utilizado deve oferecer total compatibilidade com sistemas de 64 bits. Há muito tempo não existe um sistema de proteção automática para arquivos binários de 64 bits (programa Hasp Envelop).
Portanto, o mecanismo de segurança teve que ser implementado manualmente dentro do código do programa, e essa foi uma tarefa mais difícil que exigiu profissionalismo e tempo. Não se esqueça dos assuntos relacionados à segurança, atualizações do sistema, entre outros.
3.8. Instalador
Você precisa de um novo instalador capaz de instalar completamente aplicativos de 64 bits. Gostaríamos de alertá-lo sobre um erro muito típico. É a criação de instaladores de 64 bits para instalar produtos de programas de 32/64 bits. Ao preparar a versão de 64 bits de um aplicativo, os desenvolvedores geralmente desejam tornar o "modo de 64 bits" absoluto e criar um instalador de 64 bits, esquecendo que aqueles que usam um sistema operacional de 32 bits simplesmente não conseguem iniciar esse pacote de instalação.
Preste atenção que não é o aplicativo de 32 bits incluído na distribuição junto com o de 64 bits, mas o próprio instalador. Porque se a distribuição for um aplicativo de 64 bits, é claro que não funcionará em um sistema operacional de 32 bits. O mais desagradável é que o usuário não conseguirá adivinhar por que isso está acontecendo.
Etapa 4: Configurando um projeto no Visual Studio 2005/2008
Criar a configuração de 64 bits de um projeto no Visual Studio parece bastante simples. As dificuldades começarão na fase de construção de uma nova configuração e detecção de erros nela. Para criar a configuração de 64 bits propriamente dita, você precisa executar as 4 etapas a seguir:
Passo 1: Inicie o gerenciador de configuração, conforme mostrado na imagem 1:
Passo 2: No gerenciador de configuração, escolha o suporte à nova plataforma:
Passo 3: escolha a plataforma 64 bits (x64) e, como base, a configuração da versão 32 bits. O Visual Studio corrigirá automaticamente as configurações que influenciam o modo de compilação.
Passo 4: A adição de uma nova configuração foi concluída e agora você pode escolher a versão de configuração de 64 bits e começar a construir um aplicativo de 64 bits. A escolha da configuração de 64 bits para a compilação é mostrada na imagem 4 4.
Se tiver sorte, não será necessário configurar adicionalmente um projeto de 64 bits. Mas depende muito do projeto, da sua complexidade e do número de bibliotecas utilizadas. A única coisa que você precisa mudar imediatamente é o tamanho da pilha. Se o tamanho de heap no seu projeto estiver definido por padrão, que é 1 MB, você deve defini-lo como 2 MB para a versão de 64 bits.
Não é necessário, mas é melhor ter certeza de antemão. Se você usar um tamanho diferente do padrão, faz sentido aumentá-lo duas vezes para a versão de 64 bits. Para fazer isso, encontre e altere os parâmetros Tamanho da reserva de pilha y Tamanho de confirmação da pilha nas configurações do projeto.
Etapa 5: crie um aplicativo
Aqui devemos falar sobre os problemas típicos que ocorrem na fase de compilação da configuração de 64 bits, discutir quais problemas ocorrem em bibliotecas de terceiros, dizer que no código relacionado às funções WinAPI o compilador não permitirá colocar um ponteiro no tipo LONG, e você terá que atualizar seu código e usar o tipo LONG_PTG. E há muito mais a dizer.
Infelizmente, existem tantos problemas e os erros variam tanto que não podemos descrevê-los todos em um artigo, ou mesmo em um livro. Você terá que revisar todos os erros que o compilador mostra e todos os novos avisos que não existiam antes e, em cada caso particular, descobrir como atualizar o código.
Descreveremos aqui apenas os tipos que podem ser de interesse dos desenvolvedores ao portar aplicativos. A maioria dos erros de recompilação estará relacionada ao uso destes mesmos tipos:
- Em t 32/32: tipo básico. Em sistemas de 64 bits ainda é de 32 bits.
- Longo 32/32: tipo básico. Em sistemas Windows de 64 bits, ainda é de 32 bits. Observe que em sistemas Linux 64 bits, esse tipo foi estendido para 64 bits. Não se esqueça disso se você desenvolver código que deva ser compilado para sistemas Windows e Linux.
- tamanho_t 32/64: tipo básico não assinado. O tamanho do tipo é escolhido de forma que você possa escrever nele o tamanho máximo de um array que é teoricamente possível. Você pode colocar com segurança um ponteiro para o tipo size_t (exceto para ponteiros para funções de classe, mas este é um caso especial).
- ptrdiff_t 32/64: semelhante ao tipo size_t, mas este é um tipo assinado. O resultado da expressão onde um ponteiro é subtraído do outro (ptr1-ptr2) terá o tipo ptrdiff_t.
- Ponteiro 32/64: O tamanho do ponteiro depende diretamente do tamanho da plataforma. Tenha cuidado ao converter ponteiros para outros tipos.
- __int64 64/64: Tipo assinado de 64 bits.
- DWORD32/32: Tipo não assinado de 32 bits. No WinDef.h é definido como: typedef unsigned long DWORD;
- DWORDLONG 64/64: Tipo não assinado de 64 bits. No WinNT.h é definido como: typedef ULONGLONG DWORDLONG.
- DWORD_PTR 32/64: tipo não assinado no qual um ponteiro pode ser colocado. Em BaseTsd.h é definido como: typedef ULONG_PTR DWORD_PTR.
- DWORD32 32/32: Tipo não assinado de 32 bits. Em BaseTsd.h é definido como: typedef unsigned int DWORD32.
- DWORD64 64/64: Tipo não assinado de 64 bits. Em BaseTsd.h é definido como: typedef unsigned __int64 DWORD64.
- MEIO_PTR 16/32: meio ponteiro. Em Basetsd.h é definido como: #ifdef _WIN64. typedef int HALF_PTR; #else typedef short HALF_PTR; #endif
- INT_PTR 32/64: tipo assinado no qual um ponteiro pode ser colocado. Em BaseTsd.h é definido como: #if definido (_WIN64) typedef __int64 INT_PTR; #else typedef int INT_PTR; #endif
- Longo 32/32: tipo assinado que permaneceu de 32 bits. Portanto, em muitos casos, LONG_PTR deve agora ser utilizado. No WinNT.h é definido como: typedef long LONG;
- LONG_PTR 32/64: tipo assinado no qual um ponteiro pode ser colocado. Em BaseTsd.h é definido como: #if definido (_WIN64) typedef __int64 LONG_PTR; #else typedef longo LONG_PTR; #endif.
- LPRAM 32/64: parâmetro para enviar mensagens. No WinNT.h é definido como: typedef LONG_PTR LPARAM.
- TAMANHO_T 32/64: análogo do tipo size_t. Em BaseTsd.h é definido como: typedef ULONG_PTR SIZE_T.
- SSIZE_T 32/64: Análogo do tipo ptrdiff_t. Em BaseTsd.h é definido como: typedef LONG_PTR SSIZE_T.
- ULONG_PTR 32/64: tipo não assinado no qual um ponteiro pode ser colocado. Em BaseTsd.h é definido como: #if definido (_WIN64) typedef unsigned __int64 ULONG_PTR; #else typedef não assinado longo ULONG_PTR; #endif.
- WORD 16/16: Tipo não assinado de 16 bits. No WinDef.h é definido como: typedef unsigned short WORD.
- WPARAM32/64: parâmetro para enviar mensagens. No WinDef.h é definido como: typedef UINT_PTR WPARAM.
Esses são os tipos a serem considerados ao migrar programas de 32 bits para sistemas Windows de 64 bits.
Talvez você queira saber: Como usar toda a memória RAM do Windows 10
6. Diagnóstico de erros ocultos
Se você acha que depois de corrigir todos os erros de compilação obterá um tão esperado aplicativo de 64 bits, temos que decepcioná-lo. A parte mais difícil ainda está por vir. Na fase de compilação, corrigirá os erros mais explícitos que o compilador conseguiu detectar e que estão principalmente relacionados com a impossibilidade de conversão implícita de tipo.
Mas esta é apenas uma pequena parte do problema. A maioria dos erros está oculta. Do ponto de vista da linguagem abstrata C++, esses erros parecem seguros e são disfarçados por conversões de tipo explícitas. O número desses erros é muito superior ao número de erros detectados na fase de compilação.
Você não deve colocar esperanças na chave / Wp64. Essa chave costuma ser apresentada como um meio maravilhoso de procurar erros de 64 bits. Na verdade, a chave /Wp64 simplesmente permite que você receba algumas mensagens de aviso sobre a incorreção de algumas seções do código no modo de 64 bits, enquanto o código de 32 bits está sendo compilado.
Ao compilar o código de 64 bits, esses avisos ainda serão exibidos. E é por isso que a chave /Wp64 é ignorada ao criar um aplicativo de 64 bits. E certamente esta chave não ajudará a encontrar erros ocultos. Consideremos vários exemplos de erros ocultos.
6.1. Conversão de tipo explícito
O tipo de erro mais simples (mas certamente não o mais fácil de detectar) está relacionado a conversões de tipo explícitas, quando bits significativos são cortados. Um exemplo popular é a conversão de ponteiros em tipos de 32 bits, passando-os para funções como SendMessage:
Aqui, a conversão explícita de tipo é usada para converter um ponteiro em um tipo numérico. Para uma arquitetura de 32 bits, este exemplo está correto, pois o último parâmetro da função SendMessage possui o tipo LPARAM, que corresponde a DWORD em uma arquitetura de 32 bits. Para uma arquitetura de 64 bits, DWORD está incorreto e deve ser substituído por LPRAM. O tipo LPRAM possui tamanhos de 32 ou 64 bits, dependendo da arquitetura.
Este é um caso simples, mas a conversão de tipo muitas vezes parece mais complicada e é impossível de detectar usando avisos do compilador ou pesquisando o texto do programa. As conversões de tipo explícitas suprimem o diagnóstico do compilador, uma vez que se destinam exatamente a este propósito: informar ao compilador que a conversão de tipo está correta e que o programador é responsável pela segurança do código.
A pesquisa explícita também não ajudará. Os tipos podem ter nomes não padronizados (definidos pelo programador via typedef) e o número de métodos para realizar a conversão explícita de tipos também é grande. Para diagnosticar esses erros com segurança, você deve usar um conjunto especial de ferramentas, como analisadores Viva64 ou PC-Lint.
6.2. Conversão de tipo implícita
O exemplo a seguir refere-se à conversão implícita de tipo, quando bits importantes também são perdidos. O código da função fread lê o arquivo, mas fica incorreto ao tentar ler mais de 2 GB em um sistema de 64 bits.
A função __fread retorna o tipo size_t, mas o tipo int é usado para armazenar o número de bytes lidos. Como resultado, em grandes tamanhos de dados lidos, a função pode retornar um número falso de bytes. Pode-se dizer que é um código analfabeto para iniciantes, que o compilador anunciará esse tipo de conversão e que esse código é realmente fácil de encontrar e corrigir. Isso é em teoria.
Na prática, tudo pode ser bem diferente no caso de grandes projetos. Este exemplo foi retirado do código-fonte do FreeBSD. O bug foi corrigido em dezembro de 2008! Observe que a primeira versão (experimental) de 64 bits do FreeBSD foi lançada em junho de 2003.
6.3. Bits e mudanças
É fácil cometer um erro no seu código ao trabalhar com bits separados. O próximo tipo de erro está relacionado às operações de turno. Aqui está um exemplo:
Este código funciona bem em uma arquitetura de 32 bits e permite definir bits com números de 0 a 31 para a unidade. Depois portando o programa para uma plataforma de 64 bits, você precisará definir os bits 0 a 63. Mas esse código nunca definirá os bits 32-63.
Preste atenção que "1" tem tipo int, e quando ocorrer uma alteração em 32 posições, ocorrerá um overflow conforme mostrado na imagem. O resultado de obtermos 0 (Figura B) ou 1 (Figura C) depende da implementação do compilador.
Para corrigir o código, precisamos criar uma constante "1" do mesmo tipo que a variável de máscara:
máscara ptrdiff_t = ptrdiff_t(1) << bitNum;
Preste atenção também ao fato de que códigos incorretos levam a mais um erro. Ao definir 31 bits em um sistema de 64 bits, o resultado da função será o valor 0xffffffff80000000. O resultado da expressão 1 << 31 é o número negativo -2147483648. Em uma variável inteira de 64 bits, esse número é apresentado como 0xffffffff80000000.
6.4. números mágicos
As constantes mágicas, ou seja, os números com a ajuda de que define o tamanho deste ou daquele tipo, pode causar muitos problemas. A decisão correta seria usar operadores sizeof() para esses fins, mas em um programa grande, uma seção de código antigo ainda pode estar oculta onde, como acreditam os programadores, o tamanho do ponteiro é de 4 bytes e em size_t é sempre 32 bits. Normalmente, esses erros são assim:
Abaixo estão os números básicos com os quais você deve ter cuidado ao transferir programas de 32 bits para 64 bits.
Estes com valores mágicos básicos que são perigosos ao migrar aplicativos de uma plataforma de 32 bits para 64 bits.
6.5. Erros relacionados ao uso de variáveis de 32 bits como índices
Em programas que processam grandes dados, podem ocorrer erros relacionados à indexação de grandes matrizes ou loops eternos. O exemplo a seguir contém 2 erros:
O primeiro erro aqui é que se o tamanho dos dados sendo processados exceder 4 GB (0xFFFFFFFF), um loop eterno pode ocorrer já que a variável 'Eu' tem o tipo 'não assinado' e nunca atingirá o valor 0xFFFFFFFF. Escrevemos deliberadamente que isso pode acontecer, mas não necessariamente. Depende do código que o compilador irá construir.
Por exemplo, no modo de depuração o loop eterno estará presente, e no código de lançamento não haverá loop, pois o compilador decidirá otimizar o código usando um registro de 64 bits para o contador, e o loop estará correto. Tudo isso gera muita confusão, e o código que funcionou ontem pode falhar hoje.
O segundo erro Está relacionado à análise do matriz do início ao fim para determinar quais valores de índice negativos são usados. Este código funcionará bem no modo de 32 bits, mas quando executado em um computador de 64 bits, o acesso fora dos limites ao array ocorrerá na primeira iteração do loop e o programa travará. Vamos estudar o motivo desse comportamento. De acordo com as regras de C + +, a expressão “-i – one” em um sistema de 32 bits será calculada da seguinte forma: (no primeiro passo i = 0):
A expressão "-i" possui um tipo sem sinal e um valor 0x00000000u.
A variável 'um'será estendido do tipo'int'para o tipo não assinado e será igual a 0x00000001u. Nota: o tipo int estende (de acordo com o padrão C++) até o tipo 'não assinado'se estiver participando de uma operação onde o segundo argumento tem tipo unsigned. É realizada uma operação de subtração na qual participam dois valores do tipo não assinado, e o resultado da operação é 0x00000000u – 0x00000001u = 0xFFFFFFFFu. Observe que o resultado terá tipo não assinado.
Em um sistema de 32 bits, acessar o array pelo índice 0xFFFFFFFFu é o mesmo que usar o índice -1. Aquilo é fim [0xFFFFFFFFu], é um análogo do final [-1]. Como resultado, os elementos da matriz serão processados corretamente. Em um sistema de 64 bits, a situação será bem diferente do último ponto.
O tipo não assinado será estendido para o tipo ptfdiff_t assinado e o índice do array será igual a 0x00000000FFFFFFFi64. Como resultado, ocorrerá um estouro. Para corrigir o código, você deve usar os tipos ptrdiff_t e tamanho_t.
6.6. Erros relacionados à alteração dos tipos de funções usadas
Existem erros que não são culpa de ninguém, mas ainda assim são erros. Imagine que há muito, muito tempo, em uma galáxia distante (no Visual Studio 6.0), foi desenvolvido um projeto contendo a classe CSampleApp, sucessora de CWinApp. Na classe base existe uma função virtual WinHelp. O sucessor sobrepõe esta função e executa todas as ações necessárias. Este processo é mostrado na figura a seguir.
Posteriormente, o projeto foi transferido para o Visual Studio 2005, onde o protótipo da função WinHelp mudou, mas ninguém percebeu porque no modo de 32 bits os tipos DWORD e DWORD_PTR correspondiam e o programa continuava funcionando corretamente.
O bug está aguardando para ser revelado em um sistema de 64 bits, onde os tipos DWORD e DWORD_PTR possuem tamanhos diferentes. Acontece que no modo de 64 bits, as classes contêm duas funções WinHelp DIFERENTES, o que certamente está errado. Observe que essas armadilhas podem ser ocultadas não apenas no MFC, onde algumas das funções agora possuem outros tipos de argumentos, mas também no código de seus aplicativos e bibliotecas de terceiros.
6.7. Diagnóstico de erros ocultos
Existem muitos exemplos desses tipos de erros de 64 bits. Como você pode perceber, a etapa de busca por erros ocultos não é uma tarefa trivial e, além disso, muitos deles ocorrerão de forma irregular e apenas com grandes entradas de dados. Os analisadores de código estático são bons para diagnosticar esses erros, pois podem verificar todo o código de uma aplicação, independentemente dos dados de entrada e da frequência de execução de suas seções em condições reais.
Faz sentido usar a análise estática tanto na fase de portabilidade de um aplicativo para plataformas de 64 bits, para encontrar a maioria dos erros desde o início, quanto no desenvolvimento posterior de soluções de 64 bits. A análise estática alertará e ensinará um programador a compreender melhor as peculiaridades dos erros relacionados a uma arquitetura de 64 bits e a escrever código mais eficiente.
Para ser justo, devemos dizer que os analisadores de código de teste Gimpel PC-Lint e Parasoft C++ possuem conjuntos de regras para diagnosticar erros de 64 bits. Mas antes de tudo, estes são analisadores de uso geral e as regras para diagnosticar erros de 64 bits estão incompletas. Em segundo lugar, eles são projetado principalmente para o modelo de dados LP64 usado na família de OS Linux, portanto, eles não são tão úteis para programas Windows que usam o modelo de dados LLP64.
Passo 7 – Atualização do Processo de Teste
A passagem de procure por erros no código do programa descrito na seção anterior é necessário, mas insuficiente. Nenhum dos métodos, incluindo a análise estática de código, pode garantir a detecção de todos os erros, e o melhor resultado só pode ser alcançado quando diferentes métodos são combinados.
Se o seu programa de 64 bits processar um tamanho de dados maior que a versão de 32 bits, você deverá expandir os testes para incluir o processamento de dados maiores que 4 GB. Este é o limite além do qual muitos erros de 64 bits começam a ocorrer. Esses testes podem demorar muito mais e você deve estar preparado para isso.
Os testes geralmente são escritos de tal forma que cada teste pode processar um pequeno número de elementos e, assim, possibilitar a execução de todos os testes unitários internos em vários minutos, enquanto os testes automatizados (por exemplo, usando AutomatedQA TestComplete) podem ser concluídos em várias horas.
A função de classificação que classifica 100 itens quase certamente se comportará corretamente em 100000 itens em um sistema de 32 bits. Mas a mesma função pode falhar em um sistema de 64 bits ao tentar processar 5 bilhões de itens. A velocidade de execução de um teste unitário pode ser reduzida milhões de vezes.
Não se esqueça do custo de adaptação de testes ao dominar sistemas de 64 bits. Uma boa solução é dividir os testes de unidade em rápidos (trabalhando com tamanhos de memória pequenos) e lentos, que processam gigabytes e são executados, por exemplo, durante a noite. Testes automatizados de programas de 64 bits com uso intensivo de recursos podem ser organizados com base em cálculos distribuídos.
Advertências
Feno mais uma coisa desagradável. Dificilmente você conseguirá usar ferramentas como o BoundsChecker para verificar erros em programas de 64 bits que consomem muitos recursos e muita memória. O motivo é uma grande lentidão nos programas testados, o que torna essa abordagem muito inconveniente.
No modo de diagnosticar todos os erros relacionados ao funcionamento da memória, a ferramenta Inspetor Paralelo incluído em Estúdio Paralelo Intel, irá desacelerar a execução de um aplicativo em 100 vezes, em média. Muito provavelmente você terá que deixar o algoritmo em teste durante a noite para ver os resultados apenas no dia seguinte, enquanto normalmente esse algoritmo opera em apenas 10 minutos.
Ainda assim, temos certeza de que o Parallel Inspector é uma das ferramentas mais úteis e convenientes ao trabalhar no modo de localização de erros de operação de memória. Você só precisa estar preparado para mudar sua prática de diagnóstico de erros e levar isso em consideração ao planejar dominar sistemas de 64 bits.
Final de Pensamientos
Não se esqueça de adicionar testes que verificam a compatibilidade do formato de dados entre as versões de 32 e 64 bits. A compatibilidade de dados é frequentemente violada durante a migração, devido à gravação de tipos como size_t ou long (em sistemas Linux) em arquivos. Este foi nosso tutorial completo sobre como transferir programas de 32 bits para 64 bits. Esperamos que você tenha tido uma boa experiência ao concluir o processo.
Meu nome é Javier Chirinos e sou apaixonado por tecnologia. Desde que me lembro, eu gostava de computadores e videogames e esse hobby acabou virando um emprego.
Publico sobre tecnologia e gadgets na Internet há mais de 15 anos, especialmente em mundobytes.com
Também sou especialista em comunicação e marketing online e tenho conhecimento em desenvolvimento WordPress.