Usando o avr-gcc como exemplo, os tipos int são especificados para ter 16 bits de largura. Executar operações em operandos de 8 bits em C resulta na conversão desses operandos em tipos int de 16 bits devido à promoção de números inteiros em C. Isso significa que todas as operações aritméticas de 8 bits em um AVR levarão muito mais tempo se forem escritas em C do que se escrito em assembly devido à promoção inteira de C?
microcontroller
avr
c
pr871
fonte
fonte
Respostas:
Longa história curta:
A promoção inteira para 16 bits sempre ocorre - o padrão C impõe isso. Mas é permitido ao compilador otimizar o cálculo de volta para 8 bits (os compiladores de sistemas embarcados geralmente são muito bons em tais otimizações), se for possível deduzir que o sinal será o mesmo que seria se o tipo tivesse sido promovido.
Isso não é sempre o caso! Alterações implícitas de assinatura causadas pela promoção de números inteiros são uma fonte comum de erros em sistemas incorporados.
Explicação detalhada pode ser encontrada aqui: Regras implícitas de promoção de tipo .
fonte
como esperado fun1 é tudo ints o mesmo acontece com a matemática de 16 bits
Embora tecnicamente incorreto, pois é uma adição de 16 bits chamada pelo código, mesmo não otimizado, esse compilador removeu o adc devido ao tamanho do resultado.
Não é surpresa que aqui a promoção aconteça, os compiladores não costumavam fazer isso, não tinham certeza de qual versão fazia com que isso acontecesse, entraram nessa no início da minha carreira e, apesar dos compiladores promoverem fora de ordem (como acima), fazendo a promoção mesmo que eu disse para fazer matemática uchar, não surpreso.
e o ideal, eu sei que é 8 bits, quero um resultado de 8 bits, então eu simplesmente disse para ele fazer 8 bits por todo o caminho.
Portanto, em geral, é melhor apontar para o tamanho do registro, que é idealmente o tamanho de um (u) int, para um mcu de 8 bits como este, os autores do compilador tiveram que fazer um compromisso ... Ponto de não criar o hábito de usando uchar para matemática que você sabe que não precisa de mais de 8 bits, como quando você move esse código ou escreve um novo código em um processador com registros maiores agora o compilador precisa começar a mascarar e a estender o sinal, o que alguns são nativos em algumas instruções, e outros não.
forçar 8 bits custa mais. Eu trapacei um pouco / muito, precisaria de exemplos um pouco mais complicados para ver mais disso de uma maneira justa.
EDIT com base na discussão dos comentários
sem surpresa. Embora por que o otimizador tenha deixado essa instrução extra, você não pode usar o ldi na r19? (Eu sabia a resposta quando perguntei).
EDIT2
para avr
para evitar o mau hábito ou não comparação de 8 bits
claramente a otimização estava ligada leva apenas um segundo para tentar com seu próprio compilador para ver como ele se compara à minha saída, mas de qualquer maneira:
E sim, o uso de bytes para variáveis de tamanho de bytes, certamente em um avr, pic, etc, economizará memória e você deseja realmente tentar conservá-lo ... se você estiver realmente usando, mas, como mostrado aqui, o mínimo possível é ficará na memória, tanto quanto possível nos registros, de modo que a economia de flash ocorre por não ter variáveis extras, a economia de memória ram pode ou não ser real.
fonte
unsigned char
portanto, ele deve executar a promoção em 16 bits, conforme necessário pelo padrão.(a<<8)|b
está sempre errado para qualquer sistema comint
16 bits.a
será implicitamente promovido para oint
qual está assinado. Casoa
mantenha um valor no MSB, você acaba transferindo esses dados para o bit de sinal de um número de 16 bits, o que invoca um comportamento indefinido.Não necessariamente, uma vez que os compiladores modernos fazem um bom trabalho na otimização do código gerado. Por exemplo, se você escrever
z = x + y;
onde estão todas as variáveisunsigned char
, o compilador precisará promovê-lasunsigned int
antes de executar os cálculos. No entanto, como o resultado final será exatamente o mesmo sem a promoção, o compilador gerará código que apenas adiciona variáveis de 8 bits.Obviamente, esse nem sempre é o caso, por exemplo, o resultado
z = (x + y)/2;
dependeria do byte superior, portanto a promoção ocorrerá. Ainda pode ser evitado sem recorrer à montagem lançando o resultado intermediário de volta paraunsigned char
.Algumas dessas ineficiências podem ser evitadas usando as opções do compilador. Por exemplo, muitos compiladores de 8 bits têm um pragma ou uma opção de linha de comando para ajustar os tipos de enumeração em 1 byte, em vez de
int
conforme exigido por C.fonte
int
, poischar
provavelmente não terá a mesma classificação de conversão queint
em qualquer plataforma.int
(sim, é inconsistente). C11 6.7.2.2Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined...