Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

564
Visualizações
¿La conversión de un puntero de función a uintptr_t / intptr_t no es válida?

Extensiones de Microsoft a C y C++ :

Para realizar la misma conversión y también mantener la compatibilidad con ANSI, puede convertir el puntero de función en un uintptr_t antes de convertirlo en un puntero de datos:

 int ( * pfunc ) (); int *pdata; pdata = ( int * ) (uintptr_t) pfunc;

Justificación de C, Revisión 5.10, abril de 2003:

Incluso con una conversión explícita, no es válido convertir un puntero de función en un puntero de objeto o un puntero en void, o viceversa .

C11:

7.20.1.4 Tipos enteros capaces de contener punteros a objetos

¿Significa que pdata = ( int * ) (uintptr_t) pfunc; en inválido?

Como dice Steve Summit:

El estándar C está escrito para asumir que los punteros a diferentes tipos de objetos, y especialmente los punteros a funciones en oposición a los tipos de objetos, pueden tener diferentes representaciones .

Mientras pdata = ( int * ) pfunc; conduce a UB, parece que pdata = ( int * ) (uintptr_t) pfunc; conduce al IB. Esto se debe a que "Cualquier tipo de puntero se puede convertir en un tipo de entero" y "Un entero se puede convertir en cualquier tipo de puntero" y uintptr_t es de tipo entero.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Dadas las definiciones

 int (*pfunc)(); int *pdata;

, las tareas

 pdata = (int *)pfunc; pdata = (int *)(uintptr_t)pfunc;

son, en mi opinión, equivalentes. En una plataforma donde los punteros de datos son del mismo tamaño o más grandes que los punteros de función, ambas asignaciones funcionarán como se desee. Pero en una plataforma en la que los punteros de datos son más pequeños que los punteros de función, ambas asignaciones eliminarán inevitablemente algunos de los bits del puntero de función, lo que dará como resultado un puntero de datos que no podrá volver a convertirse en el puntero de función original más adelante.

En particular, creo que ambas asignaciones son equivalentes a pesar de la presencia del elenco (uintptr_t) en la segunda. Creo que el elenco no logra precisamente nada.

En una plataforma donde los punteros de datos son más pequeños que los punteros de función y donde el tipo uintptr_t tiene el mismo tamaño que los punteros de datos, en la asignación

 pdata = (int *)(uintptr_t)pfunc;

, la conversión a (uintptr_t) eliminará algunos de los bits del valor de pfunc .

En una plataforma donde los punteros de datos son más pequeños que los punteros de función y donde el tipo uintptr_t tiene el mismo tamaño que los punteros de función, en la asignación

 pdata = (int *)(uintptr_t)pfunc;

, la conversión a (int *) raspará algunos de los bits del valor de pfunc .

En ambos casos, pdata terminará con solo una fracción del valor original de pfunc .

(Aquí descarto la posibilidad de arquitecturas con bits de relleno o similares. En alguna plataforma hipotética extraña donde los punteros de función son más grandes que los punteros de datos, pero los bits adicionales siempre son 0, ambas asignaciones volverían a funcionar).

(También descarté la posibilidad de que int * tenga un tamaño diferente al de void * . No estoy seguro de si eso afectaría la respuesta, si un "desvío" a través de void * es más o menos necesario al intentar un conversión de int (*)() a int * .)

over 4 years ago · Santiago Trujillo Relatório

0

La conversión a uintptr_t solo funciona si se define este tipo, lo que puede no ser el caso en sistemas heredados que usan compiladores antiguos. Sin embargo, tenga en cuenta que uintptr_t debe ser lo suficientemente grande para cualquier puntero de objeto, especialmente char * o void * , pero puede ser más pequeño que los punteros de función. Tales arquitecturas son raras hoy en día y los compiladores de Microsoft probablemente ya no las admitan, pero eran un lugar común en el mundo de 16 bits (MS/DOS, Windows 1, 2 y 3.x) donde el modelo mediano tenía punteros de código segmentados de 32 bits. y punteros de datos de 16 bits.

Tenga en cuenta también que el estándar C permite que int * y void * tengan un tamaño y una representación diferentes, aunque ningún compilador de Microsoft admite objetivos tan exóticos.

En los sistemas actuales con compiladores modernos, todos los punteros de datos y de código tienen casi siempre el mismo tamaño y representación. En realidad, este es un requisito para la compatibilidad con POSIX, por lo que la recomendación de usar una conversión intermedia a (uintptr_t) es válida y efectiva.

Para una portabilidad completa, si el objetivo es pasar un puntero de función a través de un void * , siempre puede asignar un objeto del tipo de puntero de función adecuado, inicializarlo con pfunc y pasar su dirección:

 // setting up the void * int (*pfunc)(); void *pdata = malloc(sizeof pfunc); memcpy(pdata, &pfunc, sizeof pfunc); // using the void * int (**ppfunc)() = pdata; (*ppfunc)(); // equivalent to (**ppfunc)();
over 4 years ago · Santiago Trujillo Relatório

0

¿La conversión de un puntero de función a uintptr_t / intptr_t no es válida?

No. Puede ser válido. Puede ser un comportamiento indefinido .


La conversión de un puntero de función a ìnt* no está definida. Ni a ningún puntero de objeto . Ni void * .
pdata = ( int * ) pfunc; es un comportamiento indefinido .

Se permite la conversión de un puntero de función a un tipo entero , con restricciones:

Cualquier tipo de puntero se puede convertir a un tipo entero . Salvo que se especifique lo contrario, el resultado está definido por la implementación. Si el resultado no se puede representar en el tipo entero, el comportamiento no está definido. El resultado no necesita estar en el rango de valores de ningún tipo entero. C17dr 6.3.2.3 6

También se permite un entero a un tipo de puntero.

Un entero se puede convertir en cualquier tipo de puntero. Salvo que se especifique lo contrario, el resultado está definido por la implementación, es posible que no esté correctamente alineado, que no apunte a una entidad del tipo al que se hace referencia y que sea una representación de captura. C17dr 6.3.2.3 6

void * a entero a void * se define. Se define el puntero de objeto hacia/desde void* . Entonces, los tipos opcionales (u)intptr_t son suficientes para el éxito de ida y vuelta. Sin embargo, estamos preocupados por un puntero de función . A menudo, los punteros de función son más anchos que un int * .

Por lo tanto, convertir un puntero de función a int * solo tiene sentido a través de un tipo entero, más ancho mejor.

VS puede recomendar a través del tipo opcional uintptr_t y probablemente sea suficiente si la información no tiene pérdidas en otras plataformas. Sin embargo, uintmax_t puede permitir una menor pérdida de información, especialmente en el puntero de función al paso de entero, por lo que sugiero pedantemente:

 pdata = ( int * ) (uintmax_t) pfunc;

Independientemente de los pasos que se tomen, es probable que el código se convierta en una implementación específica y merece protección.

 #ifdef this && that pdata = ( int * ) (uintmax_t) pfunc; #else #error TBD code #endif
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda