Pergunta

Como um exercício, eu gostaria de escrever uma macro que me diz se uma variável inteira é assinado. Isto é o que eu tenho até agora e eu obter os resultados que esperam se eu tentar isso em uma variável de char com gcc -fsigned-char ou -funsigned-char.

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

Este é portátil? Existe uma maneira de fazer isso sem destruir o valor da variável?

Foi útil?

Solução

#define ISVARSIGNED(V)  ((V)<0 || (-V)<0 || (V-1)<0)

não muda o valor de V. O terceiro punhos de teste o caso em que V == 0.

No meu compilador (gcc / cygwin) Isso funciona para int e long, mas não para char ou short.

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)

também faz o trabalho em dois ensaios.

Outras dicas

Se você estiver usando GCC você pode usar a palavra-chave typeof para não substituir o valor:

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })

Isso cria uma variável temporária, _V, que tem o mesmo tipo que V.

Quanto à portabilidade, eu não sei. Ele vai trabalhar na máquina elogio a dois de (tudo A.K.A. seu código nunca será executado em toda a probabilidade), e eu acredito que ele vai trabalhar em um de máquinas elogio e sinal-e-ordem de grandeza. Como uma nota lateral, se você usar typeof, você pode querer -1 elenco para typeof (V) para torná-lo mais seguro (ou seja, menos propensos a avisos de gatilho).

#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))

sem destruir o valor da variável. Mas não funciona para 0 valores.

E:

#define ISVARSIGNED(V) (((V)-(V)-1) < 0)

Uma abordagem diferente para todos os "torná-lo negativo" respostas:

#define ISVARSIGNED(V) (~(V^V)<0)

Dessa forma, não há necessidade de ter casos especiais para diferentes valores de V, uma vez ? V ? Z, V ^ V = 0.

Esta solução simples não tem efeitos colaterais, incluindo o benefício de apenas referindo-se v uma vez (o que é importante em um macro). Nós usamos a extensão gcc "typeof" para obter o tipo de v, e em seguida, lançar -1 a este tipo:

#define IS_SIGNED_TYPE(v)   ((typeof(v))-1 <= 0)

É <= em vez de apenas

Por que na terra você precisa que ele seja uma macro? Os modelos são ótimos para isso:

template <typename T>
bool is_signed(T) {
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>");
    return std::numeric_limits<T>::is_signed;
}

O que vai funcionar out-of-the-box para todos os tipos integrais fundamentais. Ele também irá falhar em tempo de compilação em ponteiros, que a versão usando apenas subtração e comparação provavelmente não.

Editar : Oops, a questão exige C. Ainda assim, os modelos são a maneira agradável: P

A característica distintiva de assinado math / não assinado é que quando você direita deslocar um número assinado, o bit mais significativo é copiado. Quando você muda um número sem sinal, os novos bits são 0.

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1))
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0

Então, basicamente, esta macro utiliza uma expressão condicional para determinar se o bit alto de um número é definido. Se não for, os conjuntos de macro-lo por bit a bit negando o número. Nós não podemos fazer uma negação aritmética, porque -0 == 0. Em seguida, deslocamento para a direita por 1 bit e testar se extensão de sinal ocorreu.

Isso pressupõe 2 complemento da aritmética, mas que normalmente é uma suposição segura.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top