2009-09-24 14 views
19

Estaba leyendo la sección del C FAQ on pointers.¿El tamaño de los punteros puede variar entre los datos y los indicadores de función?

No discute poder utilizar void * punteros para mantener los punteros de función porque los punteros a los datos y punteros a funciones pueden tener diferentes tamaños en algunas plataformas y void * sólo se garantiza ser lo suficientemente grande como para contener punteros a los datos.

¿Alguien puede dar un ejemplo de una plataforma donde los punteros a los datos y los punteros a las funciones en realidad tienen diferentes tamaños?

+0

Duplicado de: http://stackoverflow.com/questions/916051/are-there-are-any-platforms-where-pointers-to-different-types-have-different-size – dmckee

+0

@dmckee, IMO, not un duplicado. – strager

+2

@strager: No, el original es * más * completo. Pero este no debería ser eliminado, porque sospecho que su título es más buscable, y tiene algunas buenas respuestas – dmckee

Respuesta

11
> type ppp.c 
#include <stdio.h> 
#include <stdlib.h> 

int global = 0; 

int main(void) { 
    int local = 0; 
    static int staticint = 0; 
    int *mall; 
    int (*fx)(void); 

    fx = main; 
    mall = malloc(42); /* assume it worked */ 
    printf("#sizeof pointer to local: %d\n", (int)sizeof &local); 
    printf("#sizeof pointer to static: %d\n", (int)sizeof &staticint); 
    printf("#sizeof pointer to malloc'd: %d\n", (int)sizeof mall); 
    printf("#sizeof pointer to global: %d\n", (int)sizeof &global); 
    printf("#sizeof pointer to main(): %d\n", (int)sizeof fx); 
    free(mall); 
    return 0; 
} 
> tcc -mc ppp.c 
Turbo C Version 2.01 ... 
warnings about unused variables elided ... 
Turbo Link Version 2.0 ... 
> ppp 
#sizeof pointer to local: 4 
#sizeof pointer to static: 4 
#sizeof pointer to malloc'd: 4 
#sizeof pointer to global: 4 
#sizeof pointer to main(): 2 
> tcc -mm ppp.c 
> ppp 
#sizeof pointer to local: 2 
#sizeof pointer to static: 2 
#sizeof pointer to malloc'd: 2 
#sizeof pointer to global: 2 
#sizeof pointer to main(): 4 

tcc -mc genera código en el modelo "compacto"; tcc -mm genera código en el modelo "medio"

+0

Supongo que esto es en una máquina X86? –

+4

... x86 modo real de 16 bits – Clifford

+0

Creo que es X86 ... No estoy seguro. Ejecuto DOS dentro de una máquina virtual en un host Linux x86-64. – pmg

8

En el modo real x86, se accede al código & por segmento + desplazamiento, cada uno de una cantidad de 16 bits. Los punteros "cercanos" solo eran de 16 bits y usaban el segmento actual, los punteros "Lejos" eran de 32 bits y especificaban el segmento y el desplazamiento. Para compiladores de C, había varios modelos de memoria diferentes que podía elegir, con diferentes valores predeterminados de punteros cercanos o lejanos para código y datos.

Por ejemplo, el modelo de memoria "Medio" se utiliza cerca de los punteros para los datos pero los indicadores lejanos para el código de forma predeterminada.

No me sorprendería que algunos procesadores incorporados modernos tengan modelos de memoria similares.

+0

El viejo DOS y los primeros entornos de Windows eran así, con algunos compiladores. – Novelocrat

+2

@Pavel: la pregunta es directamente sobre punteros de función y punteros de datos, no entre diferentes tipos de datos. – Michael

+1

Eh, necesito anteojos nuevos :( –

1

Es una situación "depende". En C++, recuerdo que los punteros a la función miembro son en realidad dos punteros en tamaño, pero que pueden ser puramente un detalle de implementación.

En algunos de los sistemas muy viejos pre-PC también puede tener un tamaño de puntero dependerá de lo que se está haciendo referencia (pero entonces también podría tener caracteres de 11 bits: D)

+3

Es prácticamente imposible implementar un puntero de función miembro en C++ en menos de 2 palabras de máquina, porque 1) el envío a través del puntero de miembro debe ser virtual, por lo que no se puede almacenar dirección del método y 2) es legal declarar punteros de miembro a clases declaradas hacia delante, por lo que no se sabe si la clase tiene algún método virtual de antemano. –

4

máquinas que utilizan un Harvard Architecture tienen almacenamiento por separado para obtener instrucciones y datos, y tener espacios de direcciones separados para las instrucciones y los datos. En una arquitectura así, no hay una razón real para que los dos espacios de direcciones (o la memoria física que los respalda) tengan el mismo tamaño.

+1

Podría ser mejor aclarar por qué este es el caso en lugar de simplemente vincular a Wikipedia. –

+0

Bastante justo; Creo que el texto de Wikipedia es bastante informativo y pensé que era bastante claro por sí mismo, pero las personas razonables pueden diferir. –

+0

Si bien este es un buen puntero (HA) para el OP, una arquitectura de Harvard no necesita una diferencia en el tamaño de los punteros, el tamaño del espacio de direcciones sí lo hace. Puede tener 2 memorias físicas separadas incrustadas en un solo espacio de direcciones, en cuyo caso puede que no necesite distinguir entre el tamaño de los espacios vacíos y el tamaño de otros punteros. Pero estoy de acuerdo en que una máquina de arquitectura de Harvard es un lugar probable para comenzar a buscar una máquina con punteros de datos y funciones separados. – Falaina

4

Los microcontroladores PIC de 16 bits (Microchip PIC24 y dsPIC) son ejemplos de dispositivos de arquitectura de Harvard con diferentes tamaños de puntero de espacio de código y datos. Los espacios de direcciones por separado difieren en tamaño: en el chip, la memoria SRAM tiene un costo de área de chip mayor que la memoria Flash, hay mucho menos, por lo que los punteros de datos pueden ser más pequeños.

Esto también es cierto para las arquitecturas PIC12, PIC16 y PIC18 también, pero dsPIC es lo que estoy usando actualmente.

5

Tenga en cuenta que POSIX requiere punteros a objetos y punteros a funciones a ser del mismo tamaño:

2.12.3 tipos de puntero

Todos los tipos de puntero de función tendrán la misma representación que el puntero del tipo de vacío. La conversión de un puntero de función a vacío * no alterará la representación. Un valor nulo * resultante de dicha conversión se puede convertir al tipo de puntero de función original, utilizando un molde explícito, sin pérdida de información.

Nota: El estándar ISO C no lo requiere, pero se requiere para la conformidad con POSIX.

En consecuencia, los sistemas que afirman que cumple con POSIX serán uniformes. Si solo apuntas a tales máquinas, entonces no tienes que preocuparte por las diferencias.

+4

NB: A partir de 2013-03-07, esta sección parece faltar en POSIX [Tipos de datos] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_12), aunque es todavía se menciona en [Rationale] (http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xsh_chap02.html#tag_22_02_12_03). Solicité una aclaración a OpenGroup sobre si este es un error técnico en el sitio web o si se trata de un cambio sustancial en POSIX 2013 en comparación con POSIX 2008. No sé cuándo recibiré una respuesta. –

+0

¿alguna vez recibió una respuesta? – Mitch

+1

@Mitch: sí, recibí una respuesta en marzo de 2014. Básicamente, es un cambio deliberado, una respuesta a un informe de error. La discusión al respecto está disponible en http://austingroupbugs.net/view.php?id=74 donde se elimina el párrafo citado y se describe la redacción revisada para 'dlsym()'. En algún momento, necesito escribirlo correctamente. He estado pensando en hacer eso durante casi un año (y los tuits redondos nunca estuvieron disponibles). –

Cuestiones relacionadas