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.
InformationsquelleAutor ssd | 2014-11-07

6 Comentarios

  1. 20

    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:

    unsigned int offset = (uintptr_t) dst % blkLen;

    Deberá incluir stdint.h o inttypes.h tener uintptr_t disponible.

  2. 10

    El problema es que la conversión de un void* puntero a unsigned 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 un void* a uintptr_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 de intptr_t, el cual es firmado; generalmente sin firmar tipos más sentido para este tipo de cosas. uintptr_t y intptr_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:

    La asignación de funciones para la conversión de un puntero a un entero o un
    entero a un puntero se pretende ser coherente con el direccionamiento
    estructura del entorno de ejecución.

    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 de blkLen; en otras palabras, usted está tratando de determinar cómo el valor del puntero es alineados con respecto a blkLentamañ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:

    1. 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 de uintptr_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.)

    2. 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.

    • Este podría ser el más valioso comentario en relación con la cuestión. Muchas gracias. Voy a tomar en cuenta su punto de & re-editar la pregunta, para todos los seguidores a hacer uso de ella.
  3. 3

    Debido a la fundición de un void * a un unsigned 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 el int puede ser de 32 bits. Para cualquier plataforma, el sizeof(unsigned int) no está garantizada para ser sizeof(void *). Usted debe utilizar uintptr_t lugar.

  4. 2

    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

    void* foo(void *dst, ...) {
        //some code
        unsigned int blkLen = sizeof(int); //this line ok.
        uintptr_t offset = (uintptr_t) dst % blkLen; //warning here!
        //some code cont...
    }
  5. 1

    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.

    • modulo en un puntero tiene sentido para comprobar la alineación.
    • En muchos de los , pero no todos de sistemas. Ver el Cray ejemplo en la de Keith respuesta donde no iba a funcionar.
  6. 0

    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.

Dejar respuesta

Please enter your comment!
Please enter your name here