"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Layout de memória em C

Layout de memória em C

Publicado em 17/08/2024
Navegar:111

Introdução

O layout da memória refere-se a como a memória de um computador é organizada e estruturada. Ele define como a memória é dividida e utilizada por vários componentes do sistema.

Isso é crucial em C, pois impacta diretamente como variáveis, funções e estruturas de dados são armazenadas e acessadas durante a execução.

Neste artigo, aprenderemos sobre os aspectos fundamentais do layout da memória no C.

Segmentos no layout de memória C

O layout da memória em C consiste em diferentes segmentos, abaixo estão os segmentos;

  1. Segmento de texto (código).
  2. Segmento de dados.
  3. Pilha.
  4. Pilha.

O diagrama abaixo descreve o layout da memória C.

Diagram of C’s memory layout.
Agora vamos discutir os segmentos em detalhes.

Segmento de texto (código)

O segmento de texto é uma região de memória em um programa C que armazena as instruções de código de máquina compiladas. Estas instruções constituem a lógica executável do programa e são responsáveis ​​por definir o seu comportamento.

Aqui está um exemplo simples para ilustrar o conceito do segmento de texto em um programa C:

#include 

int main() {
    int x = 5;
    int y = 10;
    int sum;

    sum = x   y;
    printf("The sum of %d and %d is %d\n", x, y, sum);

    return 0;
}

O compilador converte o código-fonte em código de máquina quando este programa é compilado. Este código de máquina constitui a lógica e o comportamento de um programa e é armazenado no segmento de texto.

Embora não possamos ver diretamente o código da máquina. Podemos entender que o segmento de texto contém as instruções compiladas.

Essencialmente, o segmento de texto contém instruções que definem como o programa se comporta quando é executado.

Segmento de dados

O segmento de dados é dividido em duas partes:

  • Segmento de dados inicializado
  • segmento de dados não inicializados

Segmento de dados inicializados

O segmento de dados inicializado consiste em variáveis ​​globais, externas, estáticas (locais e globais) e globais constantes inicializadas anteriormente. O segmento de dados inicializado tem duas seções, as seções somente leitura e leitura-gravação.

Variáveis ​​com valores predefinidos que podem ser modificados, ou seja, variáveis ​​globais, externas e estáticas inicializadas (locais e globais) são armazenadas na seção leitura-gravação. As variáveis ​​constantes, por outro lado, estão na seção somente leitura.

Aqui está um exemplo que ilustra variáveis ​​armazenadas no segmento de dados inicializado, tanto nas seções de leitura-gravação quanto de somente leitura:

#include 

// Global variable (read-write section)
int globalVar = 10;

// External variable declaration (read-write section)
extern int externVar;

// Static global variable (read-write section)
static int staticGlobalVar = 20;

// Constant global variable (read-only section)
const int constGlobalVar = 30;

int main() {
    globalVar  = 5;
    staticGlobalVar  = 10;

    printf("Global variable: %d\n", globalVar);
    printf("Extern variable: %d\n", externVar);  // Assuming externVar is defined in another file
    printf("Static global variable: %d\n", staticGlobalVar);
    printf("Constant global variable: %d\n", constGlobalVar);

    return 0;
}

Isto ilustra variáveis ​​armazenadas nas seções leitura-gravação e somente leitura do segmento de dados inicializado.

Segmento de dados não inicializados

O segmento de dados não inicializados, também conhecido como segmento BSS (Bloco iniciado por símbolo), consiste em variáveis ​​globais, externas e estáticas não inicializadas (locais e globais).

Essas variáveis ​​são inicializadas com zero por padrão antes da execução do programa. Eles têm permissões de leitura e gravação. Permitindo assim que eles sejam lidos e gravados durante a execução do programa.

Exemplo:

#include 

// Uninitialized global variable (goes to the BSS segment)
int globalVar;

// Uninitialized static global variable (also goes to the BSS segment)
static int staticGlobalVar;

int main() {
    // Uninitialized local static variable (goes to the BSS segment)
    static int staticLocalVar;

    printf("Uninitialized Global Variable: %d\n", globalVar);
    printf("Uninitialized Static Global Variable: %d\n", staticGlobalVar);
    printf("Uninitialized Static Local Variable: %d\n", staticLocalVar);
    return 0;
}

Neste programa, as variáveis ​​não inicializadas conterão valores zero ou nulos por padrão. Isto se deve à inicialização automática pelo compilador. Isso mostra o comportamento das variáveis ​​​​armazenadas no segmento BSS.

Pilha

O heap é uma região de memória usada para alocação dinâmica de memória durante o tempo de execução. Isso permite que a memória seja alocada e liberada conforme necessário durante a execução do programa. Funções como malloc(), calloc(), realloc() e free() são usadas para alocação e desalocação de memória na pilha. O heap é acessível a todas as partes do programa.

Exemplo:

#include 
#include 

int main() {
    // Dynamically allocate memory for an integer variable on the heap
    int *ptr = (int *)malloc(sizeof(int));

    return 0;
    }

Este trecho de código demonstra um uso simples da alocação dinâmica de memória em C. Ele chama a atenção para as etapas envolvidas na solicitação de memória, na inicialização de um ponteiro para essa memória e no gerenciamento adequado da memória para evitar vazamentos. Embora o tratamento de erros e a desalocação de memória não estejam incluídos neste exemplo, esses são componentes cruciais para trabalhar com memória dinâmica em aplicações práticas.

Pilha

A função principal dos segmentos de pilha é gerenciar chamadas de função e armazenar variáveis ​​locais. Esta parte é crucial no layout da memória de um programa, pois controla o fluxo dentro de um programa. A pilha adota uma estrutura Last In, First Out (LIFO), o que significa que os dados adicionados mais recentemente são removidos primeiro. Isso torna a pilha muito eficiente para gerenciar variáveis ​​locais e chamadas de funções aninhadas.

Exemplo:

#include 

void functionA(int n) {
    int a = n   1; // Local variable
    printf("In functionA, a = %d\n", a);
}

void functionB() {
    int b = 10; // Local variable
    printf("In functionB, b = %d\n", b);
    functionA(b); // Call to functionA
}

int main() {
    int x = 20; // Local variable
    printf("In main, x = %d\n", x);
    functionB(); // Call to functionB
    return 0;
}

O código explica como os stack frames armazenam variáveis ​​locais. Novos quadros de pilha são criados pelas chamadas de função e eliminados quando as funções retornam. As instruções printf facilitam a visualização dos valores das variáveis ​​locais de cada função. O fluxo de execução segue as chamadas e retornos das funções.

Conclusão

Os programadores C podem melhorar suas técnicas de codificação e obter uma melhor compreensão de como seus programas interagem com a memória dominando esses conceitos. Compreender o layout da memória é uma habilidade vital em sua caixa de ferramentas de programação, esteja você otimizando o desempenho ou solucionando um problema complexo.

Sinta-se à vontade para seguir, comentar e deixar palmas. Boa codificação!

Vamos nos conectar no LinkedIn.

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/hyoukarh/memory-layout-in-c-399a Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3