Por que as estruturas compactadas não fazem parte da linguagem C?

10

Todo compilador C oferece a opção de "empacotar" estruturas C (por exemplo __attribute__ ((__packed__)), ou #pragma pack()). Agora, todos sabemos que a embalagem é necessária, se quisermos enviar ou armazenar dados de maneira confiável. Isso também deve ter sido um requisito desde os primeiros dias da linguagem C.

Então, eu me pergunto por que estruturas compactadas não fazem parte da especificação da linguagem C? Eles não estão nem no C99 nem no C11, embora a necessidade de tê-los seja conhecida há décadas? O que estou perdendo? Por que é específico do compilador?

grasbueschel
fonte
2
Eles não são necessários para escrever código C puro.
user253751

Respostas:

7

Eu acho que é porque depende da combinação do CPU / compilador de destino usado. Isso significa que é melhor ser uma diretiva de compilador (relacionada a isso) do que um aspecto da linguagem, porque como especificar isso? A única maneira de fazê-lo é com a união.

O artigo de Raymond fornece algumas dicas sobre por que isso é: http://www.catb.org/esr/structure-packing/

Frans Bouma
fonte
Artigo muito interessante. (+1)
Giorgio
Que dificuldade haveria em permitir que o código dissesse "Eu preciso de uma estrutura com 12 bytes; o campo X deve se comportar como um número inteiro de 32 bits armazenado como quatro octetos little-endian no deslocamento 0; o campo Y deve se comportar como um número inteiro de 64 bits armazenados como bytes octetos little-endian no deslocamento 4 "? O código para lidar com isso em qualquer plataforma não deve ser pior do que o tipo de coisa que os compiladores já precisam para os campos de bits, e nos casos em que o programador especifica o alinhamento que corresponde à máquina nativa pode ser muito mais eficiente. Em outras máquinas, seria menos eficiente, mas ainda portátil.
Supercat
5

Existem três fatores principais.

  1. Alguns processadores não podem acessar dados não alinhados (por exemplo, um número inteiro ou flutuante iniciando em um endereço ímpar). Tentar fazer dispara uma exceção.
  2. Alguns processadores podem acessar dados não alinhados, mas a um custo de desempenho.
  3. A maioria das estruturas é acessada por um único conjunto de código-fonte C / C ++, e a interoperabilidade com outros idiomas é a exceção, não a regra.

Com esses fatores em mente, o compilador padrão e todos os compiladores C / C ++ rotineiramente protegem as estruturas para garantir o alinhamento ideal do processador, mas também fornecem mecanismos para substituí-lo, se necessário, para fins de interoperabilidade.

Isso não é de modo algum algo que foi esquecido. É extremamente bem compreendido e a situação atual é planejada. As versões mais recentes do padrão C ++ têm amplo suporte para lidar com problemas de alinhamento, dos quais talvez você não esteja familiarizado.

david.pfx
fonte
Qualquer argumento que pudesse ser feito contra estruturas compactadas também poderia ser usado para justificar tornar os campos de bits um recurso opcional. O acesso a membros de estruturas compactadas seria lento em alguns processadores, rápido em outros, mas fazer com que os compiladores tentem substituir as soluções alternativas de código do usuário pela falta de recursos de acesso desalinhado por um código mais eficiente é muito mais complicado do que simplesmente ter compiladores que permitem aos programadores especificar o que eles precisam.
Supercat
@ supercat: o que você está argumentando a favor (ou contra)? Eu não entendo.
David.pfx
Sou da opinião de que os campos de bits devem ser opcionais, mas se os campos de bits forem um recurso obrigatório, faria sentido estendê-los de uma maneira que permita o controle explícito do layout da estrutura. Caso contrário, o efeito líquido é que os compiladores precisam executar 90% do trabalho necessário para o controle total do layout, mas os programadores obtêm apenas 10% do benefício.
Supercat
@supercat: os campos de bits são números inteiros e seguem as mesmas regras de ordem de layout de bits que os números inteiros: implementação definida. Os membros do Struct são ordenados nos limites de caracteres conforme declarado, possivelmente com o empacotamento inserido. Eles são conceitualmente bastante separados. [Você precisará fazer outra pergunta se quiser expandir sua proposta, mas acho que não funcionaria de jeito nenhum.]
david.pfx
0

É específico do compilador porque não está no padrão. E isso não está no padrão, porque seria difícil especificar de uma maneira que não exigiria muito esforço de implementação para compiladores de plataformas obscuras com restrições de alinhamento impostas.

E nenhum desses esforços tem muita justificativa, porque todo compilador / plataforma que qualquer pessoa que utilize um compilador C89 ou posterior se preocupa já o implementou.

soru
fonte
2
??? Você respondeu à pergunta "Por que não está no idioma padrão", dizendo: "porque não está no padrão" ...
Emilio Garavaglia
Foi o que pensei primeiro, mas, novamente, é possível especificar o recurso como "se struct for definido com a palavra-chave 'compactada', seu tamanho será garantido como o tamanho adicionado de cada membro individual. Em plataformas que não suportam acesso desalinhado à memória, o acesso a um dos valores dos membros da estrutura é um comportamento indefinido. " Isso permitiria que os desenvolvedores em plataformas sem acesso desalinhado pelo menos saber o tamanho estruturas e o deslocamento de cada membro individual ...
grasbueschel
1
Seria possível fazer o acesso não alinhado funcionar em sistemas que não o suportam em hardware, implementando estruturas como uma matriz de bytes e executando as operações de deslocamento de bits e &/ necessárias |para ler / gravar os valores de cada campo.
dan04
1
@ dan04: Em muitos processadores, um compilador pode gerar código para acesso não alinhado, mais eficiente do que usar uma sequência de leituras e trocas de bytes. Ter uma sintaxe para isso tornaria mais fácil para esses compiladores gerar código eficiente do que exigir que eles reconhecessem todas as maneiras diferentes em que os programadores podem tentar escrever código para montar bytes em tipos mais longos.
Supercat