La siguiente línea (pure c) compila limpiamente en windows (win7 64 bits + codeblocks 13 + mingw32) y debian (wheezy 32 bits + codeblocks 10 + gcc), pero plantea advertencia en kali (64 bits + codeblocks + gcc). Cualquier comentario? Quiero decir, ¿por qué me sale esta advertencia, aunque la misma línea se compila w/o cualquier advertencia en windows & debian?
void* foo(void *dst, ...) {
//some code
unsigned int blkLen = sizeof(int); //this line ok.
unsigned int offset = (unsigned int) dst % blkLen; //warning here!
//some code cont...
}
El mensaje en codeblocks es: «de error: elenco de puntero a entero de diferente tamaño [-Werror=puntero-a-int-cast]»
nota: mis opciones del compilador son -std=c99 -Werror -save-temps
(el mismo en los tres sistemas).
edit 2:
A pesar de que he conseguido han compilado w/o advertencia usando el preprocesador líneas de abajo,
@Keith Thompson (ver más abajo) tiene un punto crucial sobre el tema. Por lo tanto, mi última decisión es el uso de uintptr_t
sería una mejor opción.
edit 1:
Gracias por todos los que respondieron. Como en todas las respuestas de la nota, el problema es de 32 bits vs 64 bits problema. He insertado siguientes preprocesador líneas:
#if __linux__ // or #if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#else
#if _WIN32
#define ENVIRONMENT32
#else
#define ENVIRONMENT64
#endif
#endif //__linux__
#ifdef ENVIRONMENT64
#define MAX_BLOCK_SIZE unsigned long long int
#else
#define MAX_BLOCK_SIZE unsigned long int
#endif //ENVIRONMENT64
y luego reemplazado el problema de la línea como:
unsigned int offset = (MAX_BLOCK_SIZE) dst % blkLen;
Ahora, todo parece OK.
- en algunos sistemas/compiladores, el tamaño de un int es diferente del tamaño de un puntero. Sin embargo, para un sistema típico, el valor de offset 0…3. así que un poco de casting de el resultado del modulo a unsigned int podría solucionar el problema.
La razón de la advertencia es que el compilador sospecha que usted podría estar tratando de ida y un puntero a través de
int
y la espalda. Esta era una práctica común antes de la llegada de las máquinas de 64 bits y no es seguro o razonable. Por supuesto, aquí el compilador puede ver claramente que usted no está haciendo esto, y sería agradable si fueron lo suficientemente inteligentes como para evitar la advertencia en casos como este, pero no lo es.Una alternativa limpia que evita la advertencia, y otro mucho más desagradable problema de mal resultado cuando el valor convertido es negativo, es:
Deberá incluir
stdint.h
ointtypes.h
teneruintptr_t
disponible.El problema es que la conversión de un
void*
puntero aunsigned int
es esencialmente no-portátil.La posible diferencia en tamaño es sólo una parte del problema. Que parte del problema puede ser resuelto mediante el uso de
uintptr_t
, un tipo que se define en<stdint.h>
y<inttypes.h>
.uintptr_t
está garantizado para ser lo suficientemente ancho que la conversión de unvoid*
auintptr_t
y de nuevo será el rendimiento de la original valor de puntero (o, al menos, un valor de puntero que compara igual a la original). También hay un tipo deintptr_t
, el cual es firmado; generalmente sin firmar tipos más sentido para este tipo de cosas.uintptr_t
yintptr_t
no garantiza que existe, pero que debe existir en cualquier (C99 o posterior) en la aplicación que tiene el apropiado tipos enteros.Pero incluso si usted tiene un tipo entero, que es lo suficientemente grande como para contener un convertido puntero, el resultado no es necesariamente significativa para otra cosa que convertir a un puntero.
El estándar de C, dice, en un no-normativos de la nota de pie de página, que:
que no es útil a menos que usted sabe lo que sucederá a que abordar la estructura.
Parece estar tratando de determinar lo que el desplazamiento de la
void*
argumento es en relación al siguiente múltiplo inferior deblkLen
; en otras palabras, usted está tratando de determinar cómo el valor del puntero es alineados con respecto ablkLen
tamaño de los bloques de memoria.Si por casualidad usted sabe que eso es una cosa sensible para hacer en el sistema que está usando, eso está bien. Pero usted debe ser consciente de que las operaciones aritméticas de números enteros resultantes de puntero de las conversiones todavía son inherentemente no-portátil.
Un ejemplo concreto: he trabajado en sistemas (Cray máquinas de vectores), donde un
void*
puntero es una máquina de 64 bits de dirección (que apunta a una de 64 bits de la palabra), con un 3-bit byte offset insertada por software en la que de otro modo no utilizados de alto orden 3 bits. La conversión de un puntero a un entero simplemente se copia la representación. Cualquier aritmética de enteros en un entero es probable que el rendimiento de sentido de los resultados, si no toma esto (es cierto que las exóticas) representación en cuenta.Conclusiones:
Definitivamente debe utilizar
uintptr_t
en lugar de jugar al preprocesador trucos para determinar qué tipo entero puede utilizar. El ejecutor de su compilador ya ha hecho el trabajo de la determinación de un tipo entero, en la que se pueda mantener un convertido de puntero de valor. No hay necesidad de reinventar ese particular de la rueda. (Advertencia:<stdint.h>
fue añadido a C por la de 1999 ISO estándar. Si estás atascado utilizando una antigua compilador que no implementarlo, usted todavía podría necesitar utilizar algún tipo de#ifdef
hacks. Pero yo todavía iba a sugerir el uso deuintptr_t
si está disponible. Usted puede probar__STDC_VERSION__ >= 199901L
para la prueba de C99 conformidad — aunque algunos compiladores pueden apoyar<stdint.h>
sin el apoyo de C99.)Usted necesita estar consciente de que la conversión de un puntero a un entero y jugando con su valor no es portátil. Eso no quiere decir que no debe hacerlo; uno de C los puntos fuertes es su capacidad para soportar no portátiles de código cuando eso es lo que usted necesita.
Debido a la fundición de un
void *
a ununsigned int
es exactamente lo que la advertencia de que es la intención de detectar porque es inseguro. El puntero puede ser de 64 bits y elint
puede ser de 32 bits. Para cualquier plataforma, elsizeof(unsigned int)
no está garantizada para sersizeof(void *)
. Usted debe utilizaruintptr_t
lugar.Tal vez porque en una de 64 bits de la arquitectura que es un puntero de 64 bits de longitud y un int en sólo 32 bits de largo ?
Usted debe tratar de
Creo que se entiende la advertencia debido a que el tamaño de int depende de la implemetations eg int podría ser de 2 bytes de largo o 4 bytes de largo. Esta podría ser la razón por la advertencia(por Favor, corrígeme si me equivoco). Pero de todos modos ¿por qué estás tratando de hacer un modulo en un puntero.
Tu podido hacer el macro pero no creo que su error. Debido a que el puntero se convertirá a unsigned long long int o unsigned long int que va a ser de 32 bits y de 64 bits en 86x y 64x OS, pero su compensación variable es unsigned int, que es de 32 bits en 64x y 86x OS.
Así que yo creo que debe convertir desplazamiento también a los respectivos macro.
O simplemente se puede convertir el puntero a tiempo (es decir, unsigned int largo) y desplazamiento de tiempo (es decir, unsigned int largo) también.