Pergunta

Eu tenho trabalhado em projetos para sistemas embarcados no passado onde temos reorganizou a ordem da declaração de variáveis ??de pilha para diminuir o tamanho do executável resultante. Por exemplo, se tivéssemos:

void func()
{
    char c;
    int i;
    short s;
    ...
}

Gostaríamos de reordenar este seja:

void func()
{
    int i;
    short s;
    char c;
    ...
}

Devido a problemas de alinhamento a primeira resultou em 12 bytes de espaço de pilha a ser utilizado e a segunda uma resultou em apenas 8 bytes.

É esse comportamento padrão para compiladores C ou apenas uma lacuna do compilador que estávamos usando?

Parece-me que um compilador deve ser capaz de variáveis ??de pilha reordenar a favorecer tamanho do executável menor se quisesse. Foi-me sugerido que algum aspecto dos previne padrão C isso, mas eu não tenho sido capaz de encontrar uma fonte respeitável de qualquer forma.

Como uma pergunta bônus, isso também se aplicam aos compiladores de C ++?

Editar

Se a resposta for sim, C / C ++ compiladores pode reorganizar variáveis ??de pilha, você pode dar um exemplo de um compilador que definitivamente faz isso? Eu gostaria de ver documentação do compilador ou algo semelhante que corrobora esta afirmação.

Editar Novamente

todo mundo Obrigado por sua ajuda. Para obter a documentação, a melhor coisa que eu fui capaz de encontrar é o papel Optimal Stack atribuição das faixas horárias no GCC (pdf), por Naveen Sharma e Sanjiv Kumar Gupta, que foi apresentado no processo GCC cúpula em 2003.

O projeto em questão aqui estava usando as ADS compilador para o desenvolvimento ARM. Ela é mencionada na documentação para que compilador que as declarações de ordenação como eu mostrei pode melhorar o desempenho, bem como o tamanho da pilha, porque da forma como os endereços arquitetura ARM-Polegar calcula no quadro de pilha local. Isso compilador não reordenar automaticamente moradores locais para tirar proveito deste. O papel ligado aqui diz que a partir de 2003 GCC também não reorganizar o quadro de pilha para melhorar a localidade de referência para processadores ARM-polegar, mas isso implica que você poderia.

Eu não consigo encontrar nada que definitivamente diz que isso já foi implementado em GCC, mas acho que isso conta papel como prova de que está tudo correto. Obrigado mais uma vez.

Foi útil?

Solução

Como não há nada na proibição padrão para compiladores C ou C ++, sim, o compilador pode fazer isso.

É diferente para agregados (isto é, estruturas), onde a ordem relativa deve ser mantida, mas ainda o compilador pode inserir almofada bytes para conseguir o alinhamento preferível.

IIRC mais recentes compiladores MSVC usar essa liberdade na sua luta contra estouros de buffer de moradores.

Como uma nota lateral, em C ++, a ordem de destruição deve ser ordem inversa da declaração, mesmo que os novos pedidos de compilador o layout de memória.

(eu não posso citar capítulo e versículo, porém, esta é a partir da memória.)

Outras dicas

Não só pode o compilador reordenar o layout pilha de variáveis ??locais, pode atribuí-los aos registos, atribuí-los a viver, por vezes, nos registos e às vezes na pilha, ele pode atribuir dois locais para o mesmo slot na memória (se suas faixas ao vivo não se sobrepõem) e pode eliminar mesmo completamente variáveis.

A necessidade pilha não existe mesmo (na verdade, o padrão C99 não tem uma única ocorrência da palavra "pilha"). Então, sim, o compilador é livre para fazer o que quiser, desde que que preserva a semântica das variáveis ??com duração de armazenamento automático.

Como para um exemplo:. Eu encontrei muitas vezes uma situação onde eu não podia exibir uma variável local no depurador porque foi armazenado em um registro

O compilador é ainda livre para remover a variável da pilha e torná-lo registar apenas se análise mostra que o endereço da variável nunca é levado / utilizado.

Um compilador pode até não estar usando uma pilha em tudo para dados. Se você estiver em uma plataforma tão pequena que você está se preocupando com 8 vs 12 bytes de pilha, então é provável que haverá compiladores que têm muito especializados abordagens. (Alguns compiladores PIC e 8051 vêm à mente)

O processador que você está compilando para?

O compilador para a série de DSP do da Texas Instruments 62xx é capaz de fazer, e faz "Otimização programa inteiro." (Você pode desligá-lo)

Este é o lugar onde o seu código é reorganizada, não apenas os habitantes locais. Então ordem dos fins de execução por ser não é o que você poderia esperar.

C e C ++ não realmente prometer um modelo de memória (no sentido de dizer que a JVM), então as coisas podem ser muito diferentes e ainda legal.

Para aqueles que não sabem eles, a família 62xx são 8 instruções por ciclo de clock DSP de; em 750Mhz, eles fazem pico em 6e + 9 instruções. Alguns dos qualquer maneira tempo. Eles fazem execução paralela, mas ordenação instrução é feito no compilador, não a CPU, como um processador Intel x86.

PIC de e placas Coelho incorporado não Have pilhas menos que você pedir especialmente bem.

É especificidades do compilador, um pode fazer o seu próprio compilador que faria o inverso se ele queria que fosse assim.

Um compilador decente vai colocar variáveis ??locais nos registos se puder. Variáveis ??só devem ser colocados na pilha se houver pressão excessiva registo (não espaço suficiente), ou se o endereço da variável é tomada, o que significa que precisa para viver na memória.

Tanto quanto eu sei, não há nada que diga variáveis ??precisam ser colocados em qualquer local específico ou alinhamento na pilha para C / C ++; o compilador irá colocá-los onde quer que é melhor para o desempenho e / ou o que é conveniente para escritores de compiladores.

AFAIK não há nada na definição de C ou C ++ especificar como o compilador deve encomendar as variáveis ??locais na pilha. Eu diria que confiar no que o compilador pode fazer neste caso é uma má idéia, porque a próxima versão do seu compilador pode fazê-lo de forma diferente. Se você gastar tempo e esforço para encomendar o seu variáveis ??locais para economizar alguns bytes de pilha, aqueles poucos bytes melhor que seja realmente crítico para o funcionamento do seu sistema.

Não há necessidade de especulação ociosa sobre o que o padrão C requer ou não requer: rascunhos recentes estão disponíveis gratuitamente on-line a partir do ANSI / ISO grupo de trabalho .

Isto não responder à sua pergunta, mas aqui é o meu 2 centavos sobre um problema relacionado ...

Eu não tive o problema de otimização de espaço de pilha, mas eu tinha o problema de desalinhamento de variáveis ??duplas na pilha. A função pode ser chamada a partir de qualquer outra função e o valor de ponteiro de pilha pode ter qualquer valor alinhados-un. Então, eu vim com a idéia adiante. Este não é o código original, eu só escrevi ...

#pragma pack(push, 16)

typedef struct _S_speedy_struct{

 double fval[4];
 int64  lval[4];
 int32  ival[8];

}S_speedy_struct;

#pragma pack(pop)

int function(...)
{
  int i, t, rv;
  S_speedy_struct *ptr;
  char buff[112]; // sizeof(struct) + alignment

  // ugly , I know , but it works...
  t = (int)buff;
  t +=  15; // alignment - 1
  t &= -16; // alignment
  ptr = (S_speedy_struct *)t;

  // speedy code goes on...
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top