Existe alguma maneira de usar um sizeof
em uma macro de pré-processador?
Por exemplo, houve uma tonelada de situações ao longo dos anos em que eu queria fazer algo como:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
A coisa exata que estou verificando aqui está completamente inventada - o que quero dizer é que geralmente gosto de incluir esses tipos de (tamanho ou alinhamento) verificações de tempo de compilação para evitar que alguém modifique uma estrutura de dados que poderia desalinhar ou re- dimensionar coisas que os quebrariam.
Desnecessário dizer - não pareço ser capaz de usar um sizeof
da maneira descrita acima.
Respostas:
Existem várias maneiras de fazer isso. Os snippets a seguir não produzirão nenhum código se
sizeof(someThing)
iguaisPAGE_SIZE
; caso contrário, eles produzirão um erro em tempo de compilação.1. caminho C11
Começando com C11, você pode usar
static_assert
(requer#include <assert.h>
).Uso:
2. Macro personalizada
Se você apenas deseja obter um erro de tempo de compilação quando
sizeof(something)
não é o que você esperava, você pode usar a seguinte macro:Uso:
Este artigo explica em detalhes por que funciona.
3. Específico de MS
No compilador Microsoft C ++, você pode usar a macro C_ASSERT (requer
#include <windows.h>
), que usa um truque semelhante ao descrito na seção 2.Uso:
fonte
gcc
(testado na versão 4.8.4) (Linux). No((void)sizeof(...
caso de erros comexpected identifier or '(' before 'void'
eexpected ')' before 'sizeof'
. Mas, em princípiosize_t x = (sizeof(...
, funciona como pretendido. Você tem que "usar" o resultado de alguma forma. Para permitir que isso seja chamado várias vezes dentro de uma função ou no escopo global, algo comoextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
pode ser usado repetidamente (sem efeitos colaterais, não faça referência a_BUILD_BUG_ON_
nenhum lugar).Não. As diretivas condicionais usam um conjunto restrito de expressões condicionais;
sizeof
é uma das coisas não permitidas.As diretivas de pré-processamento são avaliadas antes que a fonte seja analisada (pelo menos conceitualmente), portanto, não há nenhum tipo ou variável para obter seu tamanho.
No entanto, existem técnicas para obter asserções de tempo de compilação em C (por exemplo, consulte esta página ).
fonte
Eu sei que é uma resposta tardia, mas para acrescentar à versão de Mike, aqui está uma versão que usamos que não aloca nenhuma memória. Eu não vim com a verificação do tamanho original, encontrei na internet anos atrás e infelizmente não posso citar o autor. Os outros dois são apenas extensões da mesma ideia.
Por serem typedef's, nada é alocado. Com __LINE__ no nome, é sempre um nome diferente para que possa ser copiado e colado quando necessário. Isso funciona em compiladores MS Visual Studio C e compiladores GCC Arm. Não funciona no CodeWarrior, CW reclama da redefinição, não fazendo uso da construção do pré-processador __LINE__.
fonte
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Eu sei que este tópico é muito antigo, mas ...
Minha solução:
Contanto que essa expressão seja igual a zero, ela compila bem. Qualquer outra coisa e explodirá bem ali. Como a variável é externa, ela não ocupará espaço e, desde que ninguém faça referência a ela (o que eles não farão), não causará um erro de link.
Não tão flexível quanto a macro assert, mas não consegui compilar na minha versão do GCC e isso irá ... e acho que irá compilar em qualquer lugar.
fonte
As respostas existentes mostram apenas como obter o efeito de "afirmações em tempo de compilação" com base no tamanho de um tipo. Isso pode atender às necessidades do OP neste caso específico, mas há outros casos em que você realmente precisa de uma condicional de pré-processador com base no tamanho de um tipo. Veja como fazer:
Escreva para você mesmo um pequeno programa C como:
Compile isso. Escreva um script em sua linguagem de script favorita, que executa o programa C acima e captura sua saída. Use essa saída para gerar um arquivo de cabeçalho C. Por exemplo, se você estiver usando Ruby, pode ser parecido com:
Em seguida, adicione uma regra ao seu Makefile ou outro script de construção, que fará com que ele execute o script acima para construir
sizes.h
.Inclua
sizes.h
sempre que for necessário usar condicionais de pré-processador com base em tamanhos.Feito!
(Você já digitou
./configure && make
para construir um programa? O que osconfigure
scripts fazem é basicamente igual ao descrito acima ...)fonte
E a próxima macro:
Por exemplo, em comentário, o MSVC diz algo como:
fonte
#if
diretiva de pré - processador.Apenas como referência para esta discussão, relato que alguns compiladores obtêm sizeof () ou tempo de pré-processador.
A resposta do JamesMcNellis está correta, mas alguns compiladores passam por essa limitação (isso provavelmente viola o ansi c estrito).
Nesse caso, refiro-me ao compilador IAR C (provavelmente o líder para microcontrolador profissional / programação embarcada).
fonte
sizeof
no momento do pré-processamento.sizeof
deve ser tratado apenas como um identificador.#if (sizeof(int) == 8)
realmente funcionavam (em alguns compiladores)." A resposta: "Deve ter sido antes do meu tempo.", Foi de Dennis Ritchie.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
pode funcionarfonte
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
condição. Ele não fornece nenhum benefíciosizeof(x)
.Em C11, a
_Static_assert
palavra-chave é adicionada. Pode ser usado como:fonte
No meu código c ++ portátil ( http://www.starmessagesoftware.com/cpcclibrary/ ), queria colocar uma guarda segura nos tamanhos de algumas das minhas estruturas ou classes.
Em vez de encontrar uma maneira de o pré-processador lançar um erro (que não pode funcionar com sizeof () conforme declarado aqui), encontrei uma solução aqui que faz com que o compilador emita um erro. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
Tive que adaptar esse código para que ele gerasse um erro no meu compilador (xcode):
fonte
Depois de experimentar a macro mencionada, este fragmento parece produzir o resultado desejado (
t.h
):Em execução
cc -E t.h
:Em execução
cc -o t.o t.h
:Afinal, 42 não é a resposta para tudo ...
fonte
Para verificar em tempo de compilação o tamanho das estruturas de dados em relação às suas restrições, usei este truque.
Se o tamanho de x for maior ou igual ao seu limite MAX_SIZEOF_X, o gcc reclamará com um erro de 'tamanho do array é muito grande'. O VC ++ emitirá o erro C2148 ('o tamanho total da matriz não deve exceder 0x7fffffff bytes') ou C4266 'não pode alocar uma matriz de tamanho constante 0'.
As duas definições são necessárias porque o gcc permitirá que um array de tamanho zero seja definido dessa forma (sizeof x - n).
fonte
O
sizeof
operador não está disponível para o pré-processador, mas você pode transferirsizeof
para o compilador e verificar a condição no tempo de execução:fonte
compiler_size
? O que seu exemplo tenta mostrar?