A Arqueologia dos Tipos de Dados: Por que o Windows e o Linux enxergam a memória de forma diferente?

A Arqueologia dos Tipos de Dados: Engenharia, Memória e Legado

Ao desenvolver software multiplataforma em C ou C++, desenvolvedores frequentemente encontram comportamentos bizarros: um código que funciona perfeitamente no Linux pode estourar a memória ou causar erros de tipos no Windows. O motivo não é apenas o sistema operacional, mas decisões de arquitetura que datam de décadas atrás.


1. O Fantasma da Memória Segmentada: O Prefixo “L”

Se você já viu o tipo LPWSTR no Windows, o “L” significa Long. Mas por que um ponteiro precisaria ser “longo”?

A Era do Intel 8086 (16 bits)

Nos anos 80, os processadores usavam endereços de 16 bits, o que limitava o acesso a apenas 64 KB de RAM. Para usar mais memória, a Intel criou a Segmentação. A memória era dividida em blocos (segmentos).

A Transição para o Modelo Plano (Flat Model)

Com a chegada dos 32 bits (e depois 64 bits), a segmentação morreu. A memória passou a ser vista como um único bloco contínuo.


2. Modelos de Dados: LP64 vs. LLP64

Por que o sizeof(long) é 8 no Linux e 4 no Windows? A resposta está na escolha do Modelo de Dados durante a transição para os 64 bits.

O Modelo Linux: LP64

O Linux (e a maioria dos sistemas Unix) adotou o modelo LP64.

O Modelo Windows: LLP64

O Windows adotou o LLP64.

Por que o Windows fez isso? Para evitar quebras em códigos legados. Muitos programadores de Windows assumiam que sizeof(long) == sizeof(int). Se o Windows mudasse o long para 64 bits, estruturas de dados salvas em arquivos seriam corrompidas ao serem lidas por versões novas dos programas.


3. Prova de Conceito: Testando sua Arquitetura

Use o script abaixo para verificar como o seu compilador e sistema operacional tratam esses tipos na prática.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

/**
 * PoC: Verificação de Modelos de Dados
 * Compile com: gcc main.c -o teste (Linux)
 * ou cl main.c (Windows)
 */
int main() {
    printf("=== Analise de Tipos de Dados ===\n");
    printf("Size of int:       %zu bytes\n", sizeof(int));
    printf("Size of long:      %zu bytes (Diferenca crucial aqui!)\n", sizeof(long));
    printf("Size of long long: %zu bytes\n", sizeof(long long));
    printf("Size of void*:     %zu bytes (Largura do barramento de endereco)\n", sizeof(void*));

    printf("\n=== Analise de Ponteiros ===\n");
    if (sizeof(void*) == 8) {
        printf("Arquitetura: 64-bits\n");
    } else {
        printf("Arquitetura: 32-bits\n");
    }

    return 0;
}