El fragmento:
((int8_t) + (78));
es un expresión, uno que toma el valor 78
, se aplica el operador unario +
, entonces arroja que a un tipo int8_t
, antes de tirarlo. No es real, diferente a las expresiones legales:
42;
a + 1;
que también evaluar las expresiones luego tirar el resultado (aunque éstas posiblemente se optimizarán dejar de existir si el compilador puede decir que no hay efectos secundarios).
Estas expresiones "desnudos" son perfectamente válidas en C y generalmente útiles sólo cuando tienen efectos secundarios, tales como con i++
, que calcula i
y lo lanza lejos con el efecto secundario es que se incrementa el valor.
La forma en que debe a utilizar esa macro es más a lo largo de las líneas de:
int8_t varname = INT8_C (somevalue);
La razón de la aparentemente redundante +
operador unitario se pueden encontrar en la norma. Citando 6.5.3.3 Unary arithmetic operators /1
:
El operando del operador unario + o - debe tener un tipo aritmético;
Y, en 6.2.5 Types, /18
:
enteros y tipos flotantes se denominan colectivamente tipos aritméticos.
En otras palabras, el unario +
no le permite usar todos los otros tipos de datos en la macro, tales como punteros, números complejos o estructuras.
Y, por último, la razón de su:
signed char + 78;
fragmento no funciona es porque no es lo mismo. Éste está comenzando a declarar una variable de tipo signed char
pero se ahoga cuando llega al +
ya que ese no es un nombre de variable legal. Para que sea equivalente a su fragmento de trabajo, se debería utilizar:
(signed char) + 78;
que es la fundición del valor +78
para escribir signed char
.
Y, según 7.8.14 Macros for integer constants /2
C99, también se debe tener cuidado con el uso de los no constantes en esas macros, que no está garantizado para trabajar:
El argumento en cualquier instancia de estas macros se realizará una constante entera no reajustada (como definida en 6.4.4.1) con un valor que no supera los límites para el tipo correspondiente.
6.4.4.1
simplemente especifica los diversos formatos de enteros (decimal/octal/hex) con los diversos sufijos (U
, UL
, ULL
, L
, LL
y los equivalentes minúsculas, dependiendo del tipo). La conclusión es que tienen que ser constantes en lugar de variables.
Por ejemplo, glibc
tiene:
# define INT8_C(c) c
# define INT16_C(c) c
# define INT32_C(c) c
# if __WORDSIZE == 64
# define INT64_C(c) C## L
# else
# define INT64_C(c) C## LL
# endif
que permitirá que su INT8_C
macro para funcionar bien, pero el texto INT64_C(val)
se pre-procesado en cualquiera valL
o valLL
, ninguno de los cuales usted quiere.
Cabe señalar que esta definición de 'INT8_C' es incorrecta: 7.18.4 párrafo 3: "Cada invocación de una de estas macros (NOTA: refiriéndose a' INTN_C') se ampliará a una expresión constante constante ** adecuada para su uso en las directivas de preprocesamiento '# if'. **" Ese molde no funcionará en una directiva de preprocesador, ya que los tipos (y, por lo tanto, los moldes) no existen durante el preprocesamiento. ¿Qué compilador/plataforma estás usando? Debería considerar la presentación de un informe de error sobre esto. –
@ChrisLutz: era válido en C99; se convirtió en inválido en el Corrigendum técnico 1, que está incorporado en N1256. Esto fue en respuesta a [DR # 209] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_209.htm). –
@KeithThompson - Ah. Tengo una copia de TC2, y hasta hace muy poco tiempo no estaba realmente al tanto de los Corrientes Técnicos. –