Existe uma definição de macro de uma linha para determinar o endianness da máquina. Estou usando o código a seguir, mas convertê-lo em macro seria muito longo.
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char *test_endian = (unsigned char*)&test_var;
return (test_endian[0] == 0);
}
c
architecture
macros
endianness
manav mn
fonte
fonte
0
, em vez deNULL
em seu teste final, e alterar um dostest_endian
objetos para outra coisa :-).#if
diretiva.Respostas:
Código que suporta ordens de bytes arbitrárias, pronto para ser colocado em um arquivo chamado
order32.h
:Você verificaria os sistemas little endian via
fonte
char
? Melhor usaruint8_t
e falhar se este tipo não estiver disponível (o que pode ser verificado por#if UINT8_MAX
). Observe queCHAR_BIT
é independente deuint8_t
.O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 */
Se você tiver um compilador compatível com literais compostos C99:
ou:
Em geral, porém, você deve tentar escrever um código que não dependa do endianness da plataforma host.
Exemplo de implementação independente de host-endianness de
ntohl()
:fonte
ntohl
de uma maneira que não dependa do endianness da plataforma host.Não existe um padrão, mas em muitos sistemas, incluindo
<endian.h>
lhe dará algumas definições para procurar.fonte
#if __BYTE_ORDER == __LITTLE_ENDIAN
e#elif __BYTE_ORDER == __BIG_ENDIAN
. E gerar um outro#error
sentido.<endian.h>
não está disponível no Windowsendian.h
menos que__APPLE__
ou_WIN32
seja definido.#if BYTE_ORDER == LITTLE_ENDIAN
(ouBIG_ENDIAN
) sem sublinhados antes dos nomes._BYTE_ORDER
é apenas para cabeçalhos do sistema.__BYTE_ORDER
não existe.Para detectar endianness em tempo de execução, você deve ser capaz de se referir à memória. Se você seguir o padrão C, declarar uma variável na memória requer uma declaração, mas retornar um valor requer uma expressão. Não sei como fazer isso em uma única macro - é por isso que o gcc tem extensões :-)
Se você deseja ter um arquivo .h, pode definir
e então você pode usar a
ENDIANNESS
macro como quiser.fonte
Se você quiser confiar apenas no pré-processador, terá que descobrir a lista de símbolos predefinidos. A aritmética do pré-processador não tem conceito de endereçamento.
GCC no Mac define
__LITTLE_ENDIAN__
ou__BIG_ENDIAN__
Então, você pode adicionar mais diretivas condicionais de pré-processador com base na detecção de plataforma, como
#ifdef _WIN32
etc.fonte
#define __BIG_ENDIAN__ 1
e#define _BIG_ENDIAN 1
.#define __LITTLE_ENDIAN__ 1
. Esta macro parece ser um recurso clang, não um recurso gcc. Ogcc
comando em alguns Macs não é gcc, é clang.Eu acredito que é isso que foi pedido. Eu só testei isso em uma pequena máquina endian no msvc. Alguém, por favor, confirme em uma máquina big endian.
Como uma observação lateral (específica do compilador), com um compilador agressivo, você pode usar a otimização de "eliminação de código morto" para obter o mesmo efeito que um tempo de compilação
#if
como:O acima se baseia no fato de que o compilador reconhece os valores constantes em tempo de compilação, remove inteiramente o código dentro
if (false) { ... }
e substitui o código comoif (true) { foo(); }
comfoo();
O pior cenário: o compilador não faz a otimização, você ainda obtém o código correto, mas um pouco mais lento.fonte
'ABCD'
?clang -Wpedantic -Werror -Wall -ansi foo.c
e ocorrerá um erro. (Clang e isto especificamente:-Wfour-char-constants -Werror
)Se você está procurando um teste de tempo de compilação e está usando o gcc, pode fazer:
Veja a documentação do gcc para mais informações.
fonte
__BYTE_ORDER__
está disponível desde GCC 4.6Você pode , de fato, acessar a memória de um objeto temporário usando um literal composto (C99):
Qual GCC avaliará em tempo de compilação.
fonte
#if __STDC_VERSION__ >= 199901L
.A 'biblioteca de rede C' oferece funções para lidar com endian'ness. Nomeadamente htons (), htonl (), ntohs () e ntohl () ... onde n é "rede" (ou seja, big-endian) eh é "host" (ou seja, o endian'ness da máquina que executa o código).
Essas aparentes 'funções' são (comumente) definidas como macros [consulte <netinet / in.h>], portanto, não há sobrecarga de tempo de execução para usá-las.
As macros a seguir usam essas 'funções' para avaliar o endianismo.
Além do que, além do mais:
A única vez que preciso saber o endian'ness de um sistema é quando escrevo uma variável [para um arquivo / outro] que pode ser lida por outro sistema de endian'ness desconhecido (para compatibilidade entre plataformas ) ... Em casos como esses, você pode preferir usar as funções endian diretamente:
fonte
Use uma função embutida em vez de uma macro. Além disso, você precisa armazenar algo na memória, o que é um efeito colateral não muito bom de uma macro.
Você pode convertê-lo em uma macro curta usando uma variável estática ou global, como esta:
fonte
s_endianess
definido como 1 para começar?Embora não haja um #define portátil ou algo em que se possa confiar, as plataformas fornecem funções padrão para a conversão de e para o seu 'host' endian.
Geralmente, você faz armazenamento - em disco ou rede - usando 'endian de rede', que é BIG endian, e computação local usando host endian (que em x86 é LITTLE endian). Você usa
htons()
entohs()
e amigos para converter entre os dois.fonte
fonte
Não se esqueça de que endianness não é toda a história - o tamanho de
char
pode não ser de 8 bits (por exemplo, DSP's), a negação do complemento de dois não é garantida (por exemplo, Cray), o alinhamento estrito pode ser necessário (por exemplo, SPARC, também ARM salta para o meio -endian quando desalinhado), etc, etc.Pode ser uma ideia melhor direcionar um específico arquitetura de CPU .
Por exemplo:
Observe que esta solução também não é ultra-portátil, infelizmente, pois depende de definições específicas do compilador (não existe um padrão, mas aqui está uma boa compilação de tais definições).
fonte
Experimente isto:
fonte
Por favor, preste atenção que a maioria das respostas aqui não são portáveis, uma vez que os compiladores atuais irão avaliar essas respostas em tempo de compilação (depende da otimização) e retornar um valor específico baseado em um endianness específico, enquanto o endianness real da máquina pode ser diferente. Os valores nos quais o endianness é testado, nunca chegarão à memória do sistema, portanto, o código real executado retornará o mesmo resultado, independentemente do endianness real.
Por exemplo , em ARM Cortex-M3, o endianness implementado refletirá em um bit de status AIRCR.ENDIANNESS e o compilador não pode saber esse valor em tempo de compilação.
Resultado da compilação para algumas das respostas sugeridas aqui:
https://godbolt.org/z/GJGNE2 para esta resposta,
https://godbolt.org/z/Yv-pyJ para isso resposta e assim por diante.
Para resolvê-lo, você precisará usar o
volatile
qualificador.Yogeesh H T
's resposta é a mais próxima para o uso da vida real de hoje, mas desde queChristoph
sugere solução mais abrangente, uma ligeira correção para a sua resposta faria a resposta completa, basta adicionarvolatile
à declaração da União:static const volatile union
.Isso garantiria o armazenamento e a leitura da memória, necessários para determinar o endianismo.
fonte
Se você despejar o pré-processador #defines
Normalmente, você pode encontrar coisas que irão ajudá-lo. Com lógica de tempo de compilação.
Vários compiladores podem ter diferentes definições, no entanto.
fonte
Minha resposta não é a perguntada, mas é realmente simples descobrir se seu sistema é little endian ou big endian?
Código:
fonte
Código C para verificar se um sistema é little-endian ou big-indian.
fonte
Macro para encontrar endiannes
ou
fonte