Pregunta

Me gustaría saber arquitecturas que violan los supuestos He enumerado a continuación.Además, me gustaría saber si alguna de las suposiciones es falsa para todas las arquitecturas (es decir, si alguna de ellas es completamente errónea).

  1. tamaño de (int *) == tamaño de (char *) == tamaño de (void *) == tamaño de (func_ptr *)

  2. La representación en memoria de todos los punteros para una arquitectura determinada es la misma independientemente del tipo de datos al que apunta.

  3. La representación en memoria de un puntero es la misma que la de un número entero de la misma longitud de bits que la arquitectura.

  4. Sólo el compilador prohíbe la multiplicación y división de tipos de datos de puntero.NOTA:Sí, sé que esto no tiene sentido.Lo que quiero decir es: ¿existe soporte de hardware para prohibir este uso incorrecto?

  5. Todos los valores del puntero se pueden convertir a un único número entero.En otras palabras, ¿qué arquitecturas todavía utilizan segmentos y compensaciones?

  6. Incrementar un puntero es equivalente a sumar sizeof(the pointed data type) a la dirección de memoria almacenada por el puntero.Si p es un int32* entonces p+1 es igual a la dirección de memoria 4 bytes después p.

Estoy más acostumbrado a que los punteros se utilicen en un espacio de memoria virtual contiguo.Para ese uso, generalmente puedo pensar en ellos como direcciones en una recta numérica.Ver pregunta de desbordamiento de pila Comparación de punteros.

¿Fue útil?

Solución

No puedo darte ejemplos concretos de todo esto, pero haré lo mejor que pueda.

sizeof(int *) == sizeof(char *) == sizeof(void *) == sizeof(func_ptr *)

No conozco ningún sistema en el que saber esto es falso, pero considere:

Los dispositivos móviles suelen tener cierta cantidad de memoria de sólo lectura en la que se almacena el código de programa y demás.Es posible que los valores de sólo lectura (variables constantes) se almacenen en una memoria de sólo lectura.Y dado que el espacio de direcciones ROM puede ser más pequeño que el espacio de direcciones RAM normal, el tamaño del puntero también puede ser diferente.Del mismo modo, los punteros a funciones pueden tener un tamaño diferente, ya que pueden apuntar a esta memoria de sólo lectura en la que se carga el programa y que de otro modo no se puede modificar (por lo que sus datos no se pueden almacenar en ella).

Así que no conozco ninguna plataforma en la que haya observado que lo anterior no se cumple, pero puedo imaginar sistemas en los que podría ser el caso.

La representación en memoria de todos los punteros para una arquitectura determinada es la misma independientemente del tipo de datos al que apunta.

Piense en los punteros de miembros frente a los punteros normales.No tienen la misma representación (o tamaño).Un puntero de miembro consta de un this puntero y un desplazamiento.

Y como se indicó anteriormente, es concebible que algunas CPU carguen datos constantes en un área separada de la memoria, que utiliza un formato de puntero separado.

La representación en memoria de un puntero es la misma que la de un número entero de la misma longitud de bits que la arquitectura.

Depende de cómo se defina esa longitud de bits.:) Un int en muchas plataformas de 64 bits sigue siendo de 32 bits.Pero un puntero es de 64 bits.Como ya se dijo, las CPU con un modelo de memoria segmentada tendrán punteros que constan de un par de números.Asimismo, los punteros de miembros constan de un par de números.

Sólo el compilador prohíbe la multiplicación y división de tipos de datos de puntero.

En última instancia, solo tipos de datos de punteros existir en el compilador.Con lo que trabaja la CPU no son punteros, sino números enteros y direcciones de memoria.Entonces no hay ningún otro lugar donde estas operaciones en tipos de puntero podría estar prohibido.También podría solicitarle a la CPU que prohíba la concatenación de objetos de cadena de C++.No puede hacer eso porque el tipo de cadena C++ solo existe en el lenguaje C++, no en el código de máquina generado.

Sin embargo, para responder lo que usted significar, busque las CPU Motorola 68000.Creo que tienen registros separados para números enteros y direcciones de memoria.Lo que significa que pueden prohibir fácilmente operaciones tan absurdas.

Todos los valores del puntero se pueden convertir a un único número entero.

Estás a salvo allí.Los estándares C y C++ garantizan que esto siempre sea posible, sin importar el diseño del espacio de memoria, la arquitectura de la CPU y cualquier otra cosa.En concreto, garantizan una mapeo definido por la implementación.En otras palabras, siempre puedes convertir un puntero en un número entero y luego volver a convertir ese número entero para obtener el puntero original.Pero los lenguajes C/C++ no dicen nada sobre cuál debería ser el valor entero intermedio.Eso depende del compilador individual y del hardware al que se dirige.

Incrementar un puntero equivale a agregar sizeof (el tipo de datos señalado) a la dirección de memoria almacenada por el puntero.

Una vez más, esto está garantizado.Si consideramos que conceptualmente un puntero no apunta a una dirección, apunta a una objeto, entonces esto tiene mucho sentido.Agregar uno al puntero obviamente hará que apunte al próximo objeto.Si un objeto tiene 20 bytes de longitud, al incrementar el puntero se moverá 20 bytes, de modo que pase al siguiente. objeto.

Si un puntero fuera simplemente una dirección de memoria en un espacio de direcciones lineal, si fuera básicamente un número entero, entonces incrementarlo agregaría 1 a la dirección, es decir, pasaría a la siguiente byte.

Finalmente, como mencioné en un comentario a tu pregunta, ten en cuenta que C++ es solo un lenguaje.No importa en qué arquitectura esté compilado.Muchas de estas limitaciones pueden parecer oscuras en las CPU modernas.Pero ¿qué pasa si estás apuntando a CPU de antaño?¿Qué pasa si estás apuntando a las CPU de la próxima década?Ni siquiera sabes cómo funcionarán, por lo que no puedes asumir mucho sobre ellos.¿Qué pasa si su objetivo es una máquina virtual?Ya existen compiladores que generan código de bytes para Flash, listo para ejecutarse desde un sitio web.¿Qué sucede si desea compilar su código fuente de C++ a Python?

Mantenerse dentro de las reglas especificadas en el estándar garantiza que su código funcionará en todo estos casos.

Otros consejos

No tengo ejemplos concretos del mundo real en la mente, pero la "autoridad" es el estándar C. Si hay algo que no es requerido por el estándar, se puede construir una aplicación conforme de que intencionalmente no cumplir con cualesquiera otros supuestos. Algunas de estas hipótesis son verdaderas mayoría de las veces sólo porque es conveniente implementar un puntero como un entero que representa una dirección de memoria que se pueden recuperar directamente por el procesador, pero esto es sólo una consecuencia de la "conveniencia" y no pueden ser considerados como una verdad universal.

  1. No requerido por la norma (ver esta pregunta ). Por ejemplo, sizeof(int*) puede ser desigual a size(double*). void* se garantiza que sea capaz de almacenar cualquier valor del puntero.
  2. No requerido por la norma. Por definición, el tamaño es una parte de la representación. Si el tamaño puede ser diferente, la representación puede ser diferente también.
  3. No necesariamente. De hecho, "la longitud de bits de una arquitectura" es una declaración vaga. ¿Qué es un procesador de 64 bits, en realidad? ¿Es el bus de direcciones? Tamaño de los registros? ¿Bus de datos? ¿Qué?
  4. No tiene sentido para "multiplicar" o "dividir" un puntero. Está prohibido por el compilador, pero por supuesto puede multiplicar o dividir la representación subyacente (que en realidad no tiene sentido para mí) y que se traduce en un comportamiento indefinido.
  5. Tal vez yo no entiendo su punto, pero todo en una computadora digital es sólo una especie de número binario.
  6. Sí; mas o menos. Está garantizado para apuntar a un lugar que es un sizeof(pointer_type) más lejos. No es necesariamente equivalente a la adición aritmética de un número (es decir, más es un concepto lógico aquí. La representación real es arquitectura específica)

Para 6 .: un puntero no es necesariamente una dirección de memoria. Véase, por ejemplo, " La Gran Conspiración puntero " por Stack JALF :

  

Sí, he utilizado la palabra “dirección” en el comentario anterior. Es importante darse cuenta de lo que quiero decir con esto. No me refiero a “la dirección de memoria en la que los datos se almacenan físicamente”, sino simplemente un resumen “lo que necesitamos con el fin de localizar el valor. La dirección de i podría ser cualquier cosa, pero una vez que lo tenemos, siempre se puede encontrar y modificar i ".

Y:

  

Un puntero no es una dirección de memoria! He mencionado esto antes, pero digamos que de nuevo. Los punteros son típicamente implementado por el compilador simplemente como direcciones de memoria, sí, pero no tiene que ser. "

Algunos más información sobre los punteros de la norma C99:

  • 6.2.5 §27 garantiza que void* y char* tienen representaciones idénticas, es decir, que pueden ser utilizados indistintamente sin conversión, es decir, la misma dirección se denota por el mismo patrón de bits (que no tiene por qué ser cierto para otros tipos de puntero )
  • 6.3.2.3 § 1 establece que cualquier puntero a un tipo incompleto o un objeto se puede convertir a (y desde) void* y volver de nuevo y todavía ser válido; esto no incluye los punteros de función!
  • 6.3.2.3 §6 establece que void* se puede convertir a (y desde) números enteros y 7.18.1.4 § 1 proporciona tipos apropriate intptr_t y uintptr_t; el problema: estos tipos son opcionales - la norma menciona explícitamente que no tiene por qué ser un tipo entero suficientemente grande para contener realmente el valor del puntero

sizeof(char*) != sizeof(void(*)(void)? - No en x86 en modo de 36 bits de direccionamiento (apoyados en casi todos los CPU Intel Pentium desde 1)

"La representación en memoria de un puntero es lo mismo que un número entero de la misma longitud en bits" - no hay representación en memoria en cualquier arquitectura moderna; Memoria de etiquetado no ha alcanzado gran popularidad y ya era obsoleta antes de C se ha normalizado. La memoria, de hecho, ni siquiera se sostiene sólo números enteros, partes y podría decirse que las palabras (no bytes;. Mayoría de la memoria física no le permiten leer sólo 8 bits)

"La multiplicación de los punteros es imposible" - 68000 familia; registros de dirección (las que llevan a cabo los punteros) no apoyaron que IIRC.

"Todos los punteros se pueden echar a enteros" -. No en los PIC

"Aumento T * es equivalente a añadir sizeof (T) a la dirección de memoria" - verdadero por definición. También equivalente a &pointer[1].

No sé los demás, pero para DOS, el supuesto en el # 3 es falsa. DOS es de 16 bits y utiliza varios trucos para asignar muchos más de 16 bits de valor de la memoria.

  

La representación en memoria de un puntero es el mismo que un número entero de la misma longitud en bits como la arquitectura.

Creo que esta suposición es falsa, porque en el 80186, por ejemplo, un puntero de 32 bits se lleva a cabo en dos registros (un desplazamiento para registrar una un registro de segmento), y que de media se corrió en el que se registra asuntos durante el acceso.

  

La multiplicación y la división de los tipos de datos de puntero solamente están prohibidos por el compilador.

No se puede multiplicar o dividir los tipos. ; P

No estoy seguro por qué desea multiplicar o dividir un puntero.

  

Todos los valores de puntero pueden ser fundidas a un solo número entero. En otras palabras, ¿qué arquitecturas todavía hacer uso de segmentos y desplazamientos?

El estándar C99 permite punteros a ser almacenados en intptr_t, que es un tipo entero. Así que, sí.

  

incrementar un puntero es equivalente a la adición de sizeof (el tipo de datos en punta) a la dirección de memoria almacenada por el puntero. Si p es un int32 * entonces p + 1 es igual a la dirección de memoria de 4 bytes después de p.

x + y donde x es un T * y y es un entero es equivilent a (T *)((intptr_t)x + y * sizeof(T)) por lo que yo sé. La alineación puede ser un problema, pero el relleno puede ser proporcionada en el sizeof. No estoy realmente seguro.

En general, la respuesta a todas las preguntas es "", y es que sólo aquellas máquinas que implementan lenguajes populares vieron directamente la luz del día y persistieron hasta el siglo actual. Aunque los estándares del lenguaje se reservan el derecho de modificar estas "invariantes", o afirmaciones, no ha ocurrido alguna vez en productos reales, con la posible excepción de los artículos 3 y 4, que requieren algún reexpresión de ser una verdad universal.

Es ciertamente posible construir diseños segmentados MMU, que corresponden aproximadamente con las arquitecturas basadas en capacidades que fueron populares en los últimos años académicamente, pero tal sistema no ha visto por lo general el uso común con tales características habilitadas. Tal sistema podría tener en conflicto con las afirmaciones, ya que probablemente habría tenido grandes punteros.

Además de segmentada / capacidad MMUs, que a menudo tienen grandes punteros, los diseños más extremos han intentado codificar los tipos de datos de punteros. Algunos de éstos nunca fueron construidos. (Esta pregunta nos lleva a todas las alternativas a la palabra orientada básica, un puntero-is-a-palabra arquitecturas.)

Específicamente:

  1. La representación en memoria de todos los punteros para una determinada arquitectura es la misma independientemente del tipo de datos señaló. La verdadera excepción de los diseños anteriores muy loco que trató de implementar la protección no en lenguas de tipo fuerte, pero en el hardware.
  2. La representación en memoria de un puntero es el mismo que un número entero de la misma longitud en bits como la arquitectura. Puede ser, sin duda alguna clase de tipo integral es la misma, ver LP64 vs LLP64 .
  3. La multiplicación y la división de los tipos de datos de puntero solamente están prohibidos por el compilador. derecho .
  4. Todos los valores de puntero pueden ser fundidas a un solo número entero. En otras palabras, ¿qué arquitecturas todavía hacen uso de segmentos y desplazamientos? Nada utiliza segmentos y compensaciones de hoy, pero un int C a menudo no es lo suficientemente grande, es posible que necesite un long o long long para contener un puntero.
  5. incrementar un puntero es equivalente a la adición de sizeof (el tipo de datos en punta) a la dirección de memoria almacenada por el puntero. Si p es un int32 * entonces p + 1 es igual a la dirección de memoria de 4 bytes después de p. Sí.

Es interesante notar que cada CPU Intel Architecture, es decir, cada PeeCee, contiene una unidad de segmentación elaborada de épica, legendario, complejidad. Sin embargo, se desactivará efectivamente. Cada vez que un Sistema operativo de PC arranca, establece las bases del segmento a 0 y la longitud de los segmentos a ~ 0, anulando los segmentos y dando un modelo de memoria plana.

Había un montón de "palabra dirigida" arquitecturas en los años 1950, 1960 y 1970. Pero no puedo recordar ningún ejemplo de corriente que tenían un compilador C. Recuerdo la ICL / Three Rivers PERQ máquinas en la década de 1980 que fue dirigida la palabra y tenía un permiso de escritura almacén de control (microcódigo). Uno de sus instanciaciones tenían un compilador C y una variedad de Unix llamada PNX , pero el compilador de C requiere microcódigo especial.

El problema básico es que char * tipos de palabra dirigida máquinas son torpes, sin embargo ponerlas en práctica. A menudo con sizeof(int *) != sizeof(char *) ...

Curiosamente, antes C se produjo un lenguaje llamado BCPL en el que el tipo de puntero básica era una dirección de palabra; es decir, incrementar un puntero que dio la dirección de la siguiente palabra, y ptr!1 le dio la palabra al ptr + 1. Hubo un operador diferente para abordar un byte:. ptr%42 si recuerdo

EDIT: No responder a las preguntas cuando su azúcar en la sangre es baja. Su cerebro (por cierto, la mía) no funciona como se espera. :-(

nitpick Menor:

p es un int32 * entonces p + 1

está mal, tiene que ser int32 sin firmar, de lo contrario, se ajustará a 2 GB.

rareza interesante - Tengo esto desde el autor del compilador de C para el chip Transputer - me dijo que para ese compilador, NULL se define como -2GB. ¿Por qué? Debido a que el Transputer tenía un rango de direcciones firmado: -2GB a 2 GB. ¿Puede usted creer eso? Increíble no?

Desde entonces, he conocido a varias personas que me han dicho que la definición de NULL como el que está roto. Estoy de acuerdo, pero si no lo hace se acaban de punteros NULL estar en el centro de su rango de direcciones.

Creo que la mayoría de nosotros podemos alegrarnos de que no estamos trabajando en Transputers!

Me gustaría conocer arquitecturas que violen los supuestos que he enumerado a continuación.

Veo que Stephen C mencionó las máquinas PERQ y MSalters mencionó 68000 y PIC.

Me decepciona que nadie más haya respondido la pregunta nombrando alguna de las extrañas y maravillosas arquitecturas que tienen compiladores de C que cumplen con los estándares y que no se ajustan a ciertas suposiciones injustificadas.

sizeof (int *) == sizeof (char *) == sizeof (void *) == sizeof (func_ptr *)?

No necesariamente.Algunos ejemplos:

La mayoría de los compiladores para procesadores Harvard-Architecture de 8 bits-PIC y 8051 y M8C-Make SizeOf (int *) == sizeOf (char *), pero diferente del sizeOf (func_ptr *).

Algunos de los chips muy pequeños de esas familias tienen 256 bytes de RAM (o menos) pero varios kilobytes de PROGMEM (Flash o ROM), por lo que los compiladores a menudo hacen que sizeof(int *) == sizeof(char *) sea igual a 1 (a un solo byte de 8 bits), pero sizeof(func_ptr *) igual a 2 (dos bytes de 8 bits).

Los compiladores de muchos de los chips más grandes de esas familias con unos pocos kilobytes de RAM y unos 128 kilobytes de PROGMEM hacen que sizeof(int *) == sizeof(char *) sea igual a 2 (dos bytes de 8 bits), pero sizeof( func_ptr *) igual a 3 (tres bytes de 8 bits).

Unos pocos chips de arquitectura Harvard pueden almacenar exactamente 2^16 ("64KByte") completos de PROGMEM (Flash o ROM) y otros 2^16 ("64KByte") de RAM + E/S asignadas en memoria.Los compiladores para dicho chip hacen que sizeof(func_ptr *) siempre sea 2 (dos bytes);pero a menudo tengo una manera de convertir los otros tipos de punteros sizeof(int *) == sizeof(char *) == sizeof(void *) en un "ptr largo" puntero genérico de 3 bytes que tiene el bit mágico adicional que indica si ese puntero apunta a RAM o PROGMEM.(Ese es el tipo de puntero que necesita pasar a una función "print_text_to_the_LCD()" cuando llama a esa función desde muchas subrutinas diferentes, a veces con la dirección de una cadena variable en el búfer que podría estar en cualquier lugar de la RAM, y otras veces con una de muchas cadenas constantes que podrían estar en cualquier lugar de PROGMEM).Estos compiladores suelen tener palabras clave especiales ("corto" o "cerca", "largo" o "lejos") para permitir a los programadores indicar específicamente tres tipos diferentes de punteros de caracteres en el mismo programa: cadenas constantes que sólo necesitan 2 bytes para indicar dónde en PROGMEM se ubican, cadenas no constantes que solo necesitan 2 bytes para indicar en qué parte de la RAM se encuentran, y el tipo de punteros de 3 bytes que acepta "print_text_to_the_LCD()".

La mayoría de las computadoras construidas en los años 1950 y 1960 utilizan un longitud de palabra de 36 bits o un longitud de palabra de 18 bits, con un bus de direcciones de 18 bits (o menos).He oído que los compiladores de C para este tipo de ordenadores suelen utilizar bytes de 9 bits, con sizeof (int *) == sizeof (func_ptr *) = 2 que da 18 bits, ya que todos los enteros y funciones deben estar alineados en las palabras;pero sizeof(char *) == sizeof(void *) == 4 para aprovechar instrucciones especiales PDP-10 que almacenan dichos punteros en una palabra completa de 36 bits.Esa palabra completa de 36 bits incluye una dirección de palabra de 18 bits y algunos bits más en los otros 18 bits que (entre otras cosas) indican la posición del bit del carácter señalado dentro de esa palabra.

La representación en memoria de todos los punteros para una arquitectura determinada es la misma independientemente del tipo de datos que apunte?

No necesariamente.Algunos ejemplos:

En cualquiera de las arquitecturas que mencioné anteriormente, los punteros vienen en diferentes tamaños.Entonces, ¿cómo es posible que tengan "la misma" representación?

Algunos compiladores en algunos sistemas usan "descriptores" para implementar punteros de caracteres y otros tipos de punteros.Tal descriptor es diferente para un puntero que apunta al primer "carácter" de un "char big_array[4000]" que para un puntero que apunta al primer "carácter" de un "char small_array[10]", que posiblemente son tipos de datos diferentes, incluso cuando la matriz pequeña comienza exactamente en la misma ubicación en la memoria que ocupaba previamente la matriz grande.Los descriptores permiten que dichas máquinas detecten y atrapen los desbordamientos del búfer que causan tales problemas en otras máquinas.

El "Consejos bajos en grasas" utilizados en SAFElite y "procesadores de software" similares tienen "información adicional" análoga sobre el tamaño del búfer al que apunta el puntero.Los punteros bajos en grasa tienen la misma ventaja de detectar y atrapar desbordamientos del búfer.

¿La representación en memoria de un puntero es la misma que un entero de la misma longitud de bits que la arquitectura?

No necesariamente.Algunos ejemplos:

En "arquitectura etiquetada" En las máquinas, cada palabra de memoria tiene algunos bits que indican si esa palabra es un número entero, un puntero o algo más.Con tales máquinas, mirar los bits de la etiqueta le indicaría si esa palabra era un número entero o un puntero.

He oído que las minicomputadoras Nova tienen una "broca de dirección" en cada palabra que inspiró "código de subproceso indirecto".Parece que almacenar un número entero borra ese bit, mientras que almacenar un puntero establece ese bit.

La multiplicación y la división de los tipos de datos del puntero solo están prohibidos por el compilador.NOTA:Sí, sé que esto no tiene sentido.Lo que quiero decir es: ¿hay soporte de hardware para prohibir este uso incorrecto?

Sí, parte del hardware no admite directamente este tipo de operaciones.

Como ya han mencionado otros, la instrucción "multiplicar" en el 68000 y el 6809 sólo funciona con (algunos) "registros de datos";no se pueden aplicar directamente a valores en "registros de direcciones".(Sería bastante fácil para un compilador solucionar tales restricciones: MOV esos valores desde un registro de direcciones al registro de datos apropiado y luego usar MUL).

¿Todos los valores del puntero se pueden convertir a un solo tipo de datos?

Sí.

Para poder memcpy() para funcionar correctamente, el estándar C exige que cada valor de puntero de cualquier tipo se pueda convertir en un puntero vacío ("void *").

Se requiere el compilador para que esto funcione, incluso para arquitecturas que todavía usan segmentos y compensaciones.

¿Todos los valores del puntero se pueden convertir en un solo número entero?En otras palabras, ¿qué arquitecturas todavía utilizan segmentos y compensaciones?

No estoy seguro.

Sospecho que todos los valores del puntero se pueden convertir a los tipos de datos integrales "size_t" y "ptrdiff_t" definidos en "<stddef.h>".

El incremento de un puntero es equivalente a agregar tamaño (el tipo de datos puntiagudos) a la dirección de memoria almacenada por el puntero.Si p es un int32*, entonces p+1 es igual a la dirección de memoria 4 bytes después de p.

No está claro lo que estás preguntando aquí.

P:Si tengo una matriz de algún tipo de estructura o tipo de datos primitivo (por ejemplo, un "#include <stdint.h> ... int32_t example_array[1000]; ..."), e incremento un puntero que apunta a esa matriz (por ejemplo, "int32_t p = &example_array[99];...p++;..."), ¿apunta ahora el puntero al siguiente miembro consecutivo de esa matriz, que está sizeof (el tipo de datos señalado) bytes más adelante en la memoria?

A:Sí, el compilador debe hacer que el puntero, después de incrementarlo una vez, apunte al siguiente int32_t consecutivo independiente en la matriz, sizeof (el tipo de datos señalado) bytes más adelante en la memoria, para cumplir con los estándares.

P:Entonces, si p es int32* , ¿entonces p+1 es igual a la dirección de memoria 4 bytes después de p?

A:Cuando sizeof(int32_t) es en realidad igual a 4, sí.De lo contrario, como en el caso de ciertas máquinas direccionables por palabras, incluidos algunos DSP modernos, donde sizeof(int32_t) puede ser igual a 2 o incluso 1, entonces p+1 es igual a la dirección de memoria 2 o incluso 1 "C bytes" después de p.

P:Entonces, si tomo el puntero y lo convierto en un "int"...

A:Un tipo de "Todo el mundo es una herejía VAX".

P:...y luego convertir ese "int" nuevamente en un puntero...

A:Otro tipo de "Todo el mundo es una herejía VAX".

P:Entonces, si tomo el puntero p, que es un puntero a int32_t, lo convierto en algún tipo integral que sea lo suficientemente grande como para contener el puntero, y luego agrego sizeof( int32_t ) a ese tipo integral, y luego convertir ese tipo integral nuevamente en un puntero: cuando hago todo eso, ¿el puntero resultante es igual a p+1?

No necesariamente.

Muchos DSP y algunos otros chips modernos tienen direccionamiento orientado a palabras, en lugar del procesamiento orientado a bytes que utilizan los chips de 8 bits.

Algunos de los compiladores de C para dichos chips incluyen 2 caracteres en cada palabra, pero se necesitan 2 de esas palabras para contener un int32_t, por lo que informan que sizeof( int32_t ) es 4.(He oído rumores de que existe un compilador de C para el 24 bits Motorola 56000 que hace esto).

Se requiere que el compilador organice las cosas de manera que al hacer "p++" con un puntero a int32_t se incremente el puntero al siguiente valor de int32_t.Hay varias formas en que el compilador puede hacer esto.

Una forma compatible con los estándares es almacenar cada puntero a int32_t como una "dirección de palabra nativa".Debido a que se necesitan 2 palabras para contener un único valor int32_t, el compilador de C compila "int32_t * p; ... p++" en algún lenguaje ensamblador que incrementa el valor del puntero en 2.En cambio, si ese lo hace"int32_t * p; ... int x = (int)p; x += sizeof( int32_t ); p = (int32_t *)x;", ese compilador de C para el 56000 probablemente lo compilará en lenguaje ensamblador que incrementa el valor del puntero en 4.

Estoy más acostumbrado a que los punteros se usen en un espacio de memoria virtual contiguo.

Varios PIC y 8086 y otros sistemas tienen RAM no contiguo, algunos bloques de RAM en direcciones que "hicieron el hardware más simple".Con E/S asignadas en memoria o nada en absoluto adjunto a los espacios en el espacio de direcciones entre esos bloques.

Es incluso más incómodo de lo que parece.

En algunos casos -como con el hardware de bandas de bits Se utiliza para evitar problemas causados ​​por leer-modificar-escribir -- exactamente el mismo bit en la RAM se puede leer o escribir usando 2 o más direcciones diferentes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top