AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78902674
Accepted
fghoussen
fghoussen
Asked: 2024-08-23 00:46:56 +0800 CST2024-08-23 00:46:56 +0800 CST 2024-08-23 00:46:56 +0800 CST

Na estrutura C, por que embalado, alinhado parece fazer preenchimento?

  • 772

Na estrutura C, por que packed,alignedparece fazer preenchimento?

Eu tenho que ler vários bytes MSB/LSB de um dispositivo remoto usando i2c. Como todos os dados do dispositivo são bytes, eu uso uint8_to que representa exatamente 8 bits, ou seja, 1 byte.

Agora preciso ter certeza de que a estrutura está packed(ou seja, não há "buraco" entre os elementos na estrutura), a menos que eu não leia os dados à medida que são gerados no dispositivo remoto.

Em seguida, adicionei aligneddesempenho (ou seja, permitir que a CPU leia a estrutura com acesso mínimo à memória).

Conforme explicado aqui Preenchimento e empacotamento da estrutura , o preenchimento alinha os membros da estrutura aos limites de endereço "naturais" e o empacotamento evita o preenchimento.

Este teste simples me surpreendeu:

$ gcc --version
gcc (Debian 10.2.1-6) 10.2.1 20210110

$ cat dumb.c 
#include <stdio.h>
#include <stdint.h> // uint8_t

struct struct1 {
  uint8_t msb;
} __attribute__((packed));

struct struct2 {
  uint8_t msb;
} __attribute__((packed,aligned(4)));

struct struct3 {
  uint8_t msb;
  uint8_t lsb;
} __attribute__((packed));

struct struct4 {
  uint8_t msb;
  uint8_t lsb;
} __attribute__((packed,aligned(4)));

int main(void) {
  struct struct1 s1;
  printf("sizeof(s1) %zu\n", sizeof(s1));
  struct struct2 s2;
  printf("sizeof(s2) %zu\n", sizeof(s2));
  struct struct3 s3;
  printf("sizeof(s3) %zu\n", sizeof(s3));
  struct struct4 s4;
  printf("sizeof(s4) %zu\n", sizeof(s4));
  return 0;
}

$ gcc -o dumb dumb.c

$ ./dumb 
sizeof(s1) 1
sizeof(s2) 4
sizeof(s3) 2
sizeof(s4) 4

alignedparece "preencher o final da estrutura": isso é esperado?

  • Eu esperava s2começar com um endereço de memória múltiplo de 4 bytes, mas ter tamanho 1.
  • Eu esperava s4começar com um endereço de memória múltiplo de 4 bytes, mas ter tamanho 2.

Eu li esses bytes de um dispositivo remoto para que cada byte seja transferido usando i2c do dispositivo para o PC: agora para desempenho, é melhor ir packedapenas para evitar "preenchimento extra no final", ou é melhor ir packed,alignedtransferindo e lendo bytes extras "preenchidos no final" não utilizados cada vez que há uma transferência?

c
  • 2 2 respostas
  • 60 Views

2 respostas

  • Voted
  1. Best Answer
    dbush
    2024-08-23T01:03:53+08:002024-08-23T01:03:53+08:00

    O alignedatributo em uma structdeclaração significa que qualquer instância da estrutura deve começar em um endereço alinhado.

    Isso também significa que se você tiver uma matriz de estruturas, a estrutura poderá exigir preenchimento final para que cada membro da matriz esteja alinhado corretamente.

    Embora o packedatributo minimize qualquer preenchimento usado na estrutura, esse preenchimento não pode necessariamente ser eliminado completamente quando usado em conjunto com aligned.

    Então, por exemplo, se você tivesse esta declaração:

    struct struct2 s2[2];
    

    Se você não tivesse preenchimento final, s2[1]não estaria alinhado corretamente.

    • 2
  2. John Bollinger
    2024-08-23T05:51:28+08:002024-08-23T05:51:28+08:00

    Na estrutura C, por que packed,alignedparece fazer preenchimento?

    Porque o requisito de alinhamento de um tipo de dados deve dividir seu tamanho. Caso contrário, você não poderia formar arrays desse tipo. Se você forçar um requisito de alinhamento específico, o compilador poderá precisar ajustar o tamanho (adicionando preenchimento).

    Eu tenho que ler vários bytes MSB/LSB de um dispositivo remoto usando i2c. Como todos os dados do dispositivo são bytes, eu uso uint8_t que representa exatamente 8 bits, ou seja, 1 byte.

    Agora preciso ter certeza de que a estrutura está compactada (ou seja, nenhum "buraco" entre os elementos na estrutura), a menos que eu não leia os dados à medida que são gerados no dispositivo remoto.

    Uma maneira possivelmente mais natural de fazer isso seria ler seus pares MSB/LSB em um único uint16_t, que você pode ter certeza de que não possui preenchimento interno. E como você descreve os pares dessa maneira, suponho que você queira interpretar os pares como números de 16 bits, o que pode ser convenientemente alcançado por meio da ntohs()função.

    Em seguida, adicionei alinhamento para desempenho (ou seja, permitir que a CPU leia a estrutura com acesso mínimo à memória).

    É muito provável que seja uma otimização prematura. Qualquer atraso resultante do desalinhamento provavelmente será completamente sobrecarregado pela sobrecarga de E/S.

    o preenchimento alinha os membros da estrutura aos limites de endereço "naturais",

    Mais ou menos. Esse é o propósito normal do preenchimento entre membros em layouts de estrutura, mas não é uma característica inerente desse preenchimento, nem é o único tipo de local para preenchimento.

    e a embalagem impede o preenchimento.

    Não exatamente. O significado preciso das diretivas de controle de embalagem varia entre as implementações C, mas você está usando o GCC, cuja definição é:

    packed
    Este atributo, anexado à structdefinição de tipo union, ou C++ class, especifica que cada um de seus membros [...] é colocado para minimizar a memória necessária.

    além disso,

    Especificar esse atributo para tipos structe unioné equivalente a especificar o packedatributo em cada um dos membros da estrutura ou da união.

    ... em que contexto,

    O packedatributo especifica que um membro da estrutura deve ter o menor alinhamento possível – um bit para um campo de bits e um byte caso contrário.

    Então não, isso não se refere diretamente ao preenchimento. Forçar o requisito de alinhamento para membros (não-bitfield) para 1 byte resulta no layout deles sem qualquer preenchimento inicial, mas isso não diz nada sobre se algum preenchimento segue.

    alignedparece "preencher o final da estrutura": isso é esperado?

    Sim, conforme já discutido. E isso não entra em conflito com a definição de packed.

    • Eu esperava s2começar com um endereço de memória múltiplo de 4 bytes, mas ter tamanho 1.
    • Eu esperava s4começar com um endereço de memória múltiplo de 4 bytes, mas ter tamanho 2.

    Novamente, um tipo com requisito de alinhamento de 4 terá um tamanho múltiplo de 4, portanto, suas expectativas estavam incorretas. No entanto, acho que o GCC permite alinhar variáveis ​​individuais; portanto, se você realmente deseja o que descreve, poderá alcançá-lo, para essas variáveis ​​específicas, movendo o alignedatributo dos tipos para as variáveis ​​correspondentes:

      struct struct1 s2 __attribute__((aligned(4)));
      struct struct3 s4 __attribute__((aligned(4)));
    

    Mas, novamente, acho que você está se preocupando demais com isso. Mover bytes em sua interface i2c consumirá uma grande quantidade de tempo aqui.

    Eu li esses bytes de um dispositivo remoto para que cada byte seja transferido usando i2c do dispositivo para o PC: agora para desempenho, é melhor ir packedapenas para evitar "preenchimento extra no final", ou é melhor ir packed,alignedtransferindo e lendo bytes extras "preenchidos no final" não utilizados cada vez que há uma transferência?

    Quem disse que você leria qualquer coisa em qualquer preenchimento de estrutura? Você não deveria. Se você estiver lendo bytes, um par de cada vez, não o fará. Se você estiver lendo sequências de vários pares de bytes em uma única operação, não poderá ter preenchimento. Mas, novamente, você parece estar tornando as coisas muito mais difíceis do que precisam. Eu pularia as estruturas e usaria type uint16_tpara os pares de bytes. Especialmente se você estiver lendo muitos deles juntos; nesse caso, você usaria um arquivo uint16_t[]. Supondo que você queira interpretar cada par como um número de 16 bits, pós-processe cada um após ntohs()a leitura, antes de fazer qualquer outra coisa.

    Se o resultado não for rápido o suficiente, crie um perfil para determinar onde está o gargalo e trabalhe nisso.

    • 0

relate perguntas

  • Multiplicação mais rápida que *

  • Usando uma macro para comprimento de string no especificador de formato scanf () em C

  • Como você pode definir o tipo de dados de #define para long double?

  • Ponteiros const incompatíveis

  • Mudança de cor não gradual no OpenGL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve