Por que todo mundo faz typedef sobre os tipos C padrão?

103

Se você quiser usar o Qt , terá que aceitar quint8, quint16e assim por diante.

Se você quiser usar GLib , você tem que bem-vindo guint8, guint16e assim por diante.

No Linux existem u32, s16e assim por diante.

uC / OS define SINT32, UINT16e assim por diante.

E se você tiver que usar alguma combinação dessas coisas, é melhor estar preparado para problemas. Porque em sua máquina u32vai typedefacabar longe quint32vai typedefacabar inte o compilador vai reclamar .

Por que todo mundo faz isso, se houver <stdint.h>? Isso é algum tipo de tradição para bibliotecas?

Amomum
fonte
8
@Mehrdad na programação de microcontroladores, você pode ter todos os tipos de coisas. Em AVR Mega's por exemplo (e conseqüentemente no famoso Arduino) int é de 16 bits. Isso pode ser uma surpresa desagradável. Na minha opinião, 'unsigned short' requer mais esforço de digitação. E sempre me entristecia usar 'unsigned char' para octeto <s> byte </s>. Caráter sem sinal, realmente?
Amomum
2
@Mehrdad A questão é que você não pode ter certeza. É exatamente por isso que stdint.hfoi inventado.
glglgl
1
@glglgl: Esta é outra maneira de ver o problema: você não está fazendo exatamente a pergunta errada? Se você tem como alvo vários sistemas, por que codificar arbitrariamente o número de bits no código em primeiro lugar? ou seja, por que não apenas dizer sizeof(int) * CHAR_BIT(por exemplo) e usar isso? Se seu intfor muito pequeno para representar seu intervalo (por exemplo, um índice de matriz), então quase certamente você não deveria usar de intqualquer maneira, mas algo parecido size_t. Por que int32faria mais sentido? A única vez que a largura fixa faz sentido é para a comunicação entre sistemas (por exemplo, formato de arquivo / rede) ...
user541686
1
@Mehrdad Não. Às vezes, tenho valores (como de um ADC ou qualquer outro) que preciso armazenar. Eu sei que eles têm 16 bits de largura. Portanto, o melhor ting para usar é uint16_t(ou talvez seu fastou leastvariante). Meu ponto é: esses tipos são convenientes de usar e têm sua razão de existência.
glglgl
1
@Mehrdad: Eu sugeriria que - supondo que valha a pena seu esforço para produzir código de qualidade - você deve definir seus próprios typedefs funcionais, significando a maneira de interagir com minha API / o resto do meu código , e defini-los por motivos técnicos em termos de Typedefs “técnicos” como size_te / ou uint64_t.
PJTraill de

Respostas:

80

stdint.hnão existia quando essas bibliotecas estavam sendo desenvolvidas. Assim, cada biblioteca criou seus próprios typedefs.

Edward Karak
fonte
4
E tudo bem, suponho que a falta de stdint.h seja um bom motivo, mas por que ainda hoje esses typedefs estão acima dos tipos int, long e assim, e não nos tipos stdint? Isso os tornaria intercambiáveis, pelo menos
Amomum
25
@Amomum "Por que Glib (que foi desenvolvido em Linux) não usava typedefs Linux?" Embora a "base inicial" do glib certamente seja o Linux, ele é certamente uma biblioteca portátil. Definir seus próprios tipos garante portabilidade: basta adaptar um pequeno cabeçalho que corresponda aos tipos de biblioteca aos respectivos tipos de plataforma de destino apropriados.
Peter - Reintegrar Monica
3
@Amomum Por que Glib (que foi desenvolvido em Linux) ... Não, não foi. O Glib foi criado muito antes do kernel do Linux.
andy256
5
@ andy256 "GLib" não é abreviação de "glibc". É uma biblioteca que se ramificou a partir do gtk. Não é mais antigo que o Linux.
2
@ andy256: glib é 1998, linux é 1991. IOW, GLib foi criado muito depois do Linux.
MSalters
40

Para as bibliotecas mais antigas, isso é necessário porque o cabeçalho em questão ( stdint.h) não existia.

Ainda há, no entanto, um problema: esses tipos ( uint64_te outros) são um recurso opcional no padrão. Portanto, uma implementação compatível pode não ser fornecida com eles - e assim forçar as bibliotecas a ainda incluí-los hoje em dia.

Ven
fonte
14
Os uintN_ttipos são opcionais, mas os tipos uint_leastN_te uint_fastN_tnão.
Kusalananda
7
@Kusalananda: Infelizmente, esses são de utilidade limitada.
Lightness Races in Orbit
16
Claro que a razão que eles são opcionais é que você não está garantido que não são inteiro tipos com exatamente esse número de bits. C ainda suporta arquiteturas com tamanhos inteiros bastante estranhos.
celtschk
5
@LightnessRacesinOrbit: Como eles têm utilidade limitada? Devo admitir que, além das interfaces de hardware, não vejo por que você precisaria de um número exato de bits, em vez de apenas um mínimo, para garantir que todos os seus valores se encaixem.
celtschk
23
@Amomum Os typedefs são necessários se a implementação tiver tipos que atendam aos requisitos: "No entanto, se uma implementação fornece tipos inteiros com larguras de 8, 16, 32 ou 64 bits, sem bits de preenchimento e (para os tipos assinados) que têm uma representação de complemento de dois, deve definir os nomes de typedef correspondentes. " (citação de N1570, 7.20.1.1 "Tipos inteiros de largura exata") Então, se a biblioteca padrão não os tiver, uma biblioteca de terceiros também não poderia, ao que parece.
Eric M Schmidt
13

stdint.h foi padronizado desde 1999. É mais provável que muitos aplicativos definam (efetivamente alias) tipos para manter independência parcial da arquitetura de máquina subjacente.

Eles fornecem aos desenvolvedores a confiança de que os tipos usados ​​em seus aplicativos correspondem às suposições específicas de seu projeto sobre comportamento que podem não corresponder ao padrão de linguagem ou à implementação do compilador.

A prática é espelhada no padrão de design Façade orientado a objetos e é muito utilizada pelos desenvolvedores, invariavelmente, escrevendo classes de wrapper para todas as bibliotecas importadas.

Quando os compiladores eram muito menos padronizados e as arquiteturas de máquina podiam variar de mainframes de 16 bits, 18 bits a 36 bits, isso era muito mais importante. A prática é muito menos relevante agora em um mundo convergindo para sistemas embarcados ARM de 32 bits. Continua sendo uma preocupação para microcontroladores de baixo custo com mapas de memória ímpares .

Pekka
fonte
1
Concedido, stdint.hfoi padronizado desde 1999, mas há quanto tempo está disponível na prática? As pessoas se arrastam na implementação e adoção de novos padrões e, durante esse longo período de transição, os métodos antigos ainda são essenciais.
Siyuan Ren
1
Um problema desagradável stdint.hé que mesmo em plataformas onde, por exemplo, longe int32_ttêm o mesmo tamanho e representação, não há nenhuma exigência de que a conversão de um int32_t*para long*produzirá um ponteiro que pode acessar de forma confiável um int32_t. Não posso acreditar que os autores do Padrão pensaram que era óbvio que os tipos compatíveis com layout deveriam ser compatíveis com alias, mas como eles não se preocuparam em dizer isso, os autores do gcc e IIRC clang acham que a linguagem seria melhorada ignorando até mesmo o alias nos casos em que é óbvio.
supercat de
2
@supercat - provavelmente vale a pena enviar como uma errata ao comitê C ... porque isso é gratuitamente burro , para dizer o mínimo
LThode
@LThode: Para o comitê C reconhecer isso como um erro, seria necessário que ele declarasse oficialmente o comportamento do clang e do gcc como obtuso. Você acha que isso vai acontecer? O melhor que se poderia esperar (e, IMHO, a maneira lógica de proceder) seria definir maneiras para os programas especificarem "modos de aliasing". Se um programa diz especifica que pode aceitar regras de aliasing muito rígidas, um compilador pode usar isso para permitir otimizações além do que é possível atualmente. Se um programa especifica que requer regras que são um pouco mais amigáveis ​​ao programador do que as atuais ...
supercat
... mas ainda permitiria muitas otimizações úteis, então um compilador poderia gerar um código muito mais eficiente do que seria possível -fno-strict-alias, mas que ainda funcionaria. Mesmo se não houvesse uma base de código existente, nenhum único conjunto de regras poderia atingir o equilíbrio ideal de otimização e semântica para todos os aplicativos, porque aplicativos diferentes têm necessidades diferentes. Adicione a base de código existente e a necessidade de modos diferentes deve ficar clara.
supercat
3

Portanto, você tem o poder de typedef char to int.

Um "horror da codificação" mencionou que o cabeçalho de uma empresa tinha um ponto em que um programador queria um valor booleano e um char era o tipo nativo lógico para o trabalho, e assim escreveu typedef bool char. Então, mais tarde, alguém descobriu que um inteiro era a escolha mais lógica e escreveu typedef bool int. O resultado, muito antes do Unicode, era virtualmente typedef char int.

Muita compatibilidade com visão de futuro, eu acho.

Christos Hayward
fonte