Pregunta

Como ejercicio, me gustaría escribir una macro que me diga si una variable entera tiene signo.Esto es lo que tengo hasta ahora y obtengo los resultados que espero si intento esto en una variable char con gcc -fsigned-char o -funsigned-char.

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

¿Es esto portátil?¿Hay alguna manera de hacer esto sin destruir el valor de la variable?

¿Fue útil?

Solución

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

no cambia el valor de V.La tercera prueba maneja el caso donde V == 0.

En mi compilador (gcc/cygwin) esto funciona para int y long pero no para char o short.

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

También hace el trabajo en dos pruebas.

Otros consejos

Si usa GCC, puede usar la palabra clave typeof para no sobrescribir el valor:

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

Esto crea una variable temporal, _V, que tiene el mismo tipo que V.

En cuanto a la portabilidad, no lo sé. Funcionará en la máquina de cumplidos de dos (también conocido como todo lo que su código ejecutará con toda probabilidad), y creo que funcionará también en las máquinas de cumplidos y signos y magnitudes. Como nota al margen, si usa -1, es posible que desee convertir typeof (V) a <=> para hacerlo más seguro (es decir, menos probable que active advertencias).

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

Sin destruir el valor de la variable. Pero no funciona para valores 0.

¿Qué pasa con:

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

Un enfoque diferente para todos los " que sea negativo " respuestas:

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

De esa manera no es necesario tener casos especiales para diferentes valores de V, ya que & # 8704; V & # 8712; & # 8484 ;, V ^ V = 0.

Esta solución simple no tiene efectos secundarios, incluido el beneficio de referirse solo a v una vez (lo cual es importante en una macro). Usamos la extensión gcc & Quot; typeof & Quot; para obtener el tipo de v, y luego convertir -1 a este tipo:

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

Es < = en lugar de solo < para evitar advertencias del compilador en algunos casos (cuando está habilitado).

¿Por qué demonios necesitas que sea una macro? Las plantillas son excelentes para esto:

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;
}

Que funcionará de forma inmediata para todos los tipos integrales fundamentales. También fallará en tiempo de compilación en punteros, que la versión que usa solo resta y comparación probablemente no lo hará.

EDITAR : Vaya, la pregunta requiere C. Aún así, las plantillas son la mejor manera: P

Una característica distintiva de las matemáticas con signo / sin signo es que cuando se desplaza a la derecha un número con signo, se copia el bit más significativo. Cuando cambia un número sin signo, los nuevos bits son 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

Entonces, básicamente, esta macro usa una expresión condicional para determinar si se establece el bit alto de un número. Si no es así, la macro lo establece negando bit a bit el número. No podemos hacer una negación aritmética porque -0 == 0. Luego nos desplazamos a la derecha en 1 bit y probamos si se produjo la extensión del signo.

Esto supone la aritmética del complemento a 2, pero generalmente es una suposición segura.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top