2012-02-21 15 views
7

Quiero asignar algún valor (digamos 2345) a una ubicación de memoria (digamos 0X12AED567). Se puede hacer esto?¿Podemos asignar un valor a una ubicación de memoria dada?

En otras palabras, ¿cómo puedo implementar la siguiente función?

void AssignValToPointer(uint32_t pointer, int value) 
{ 

} 
+7

'* (int *) 0x12AED567 = 2345' Pero es mejor que sepas lo que estás haciendo ... – Mysticial

+0

mejor no lo intentes a menos que estés seguro de que la memoria no está en uso –

+1

No solo la memoria debe utilizarse para ningún otro propósito , pero debe estar mapeado. En * nix al menos, si intentas escribir en una página no asignada, tu aplicación se segmenta y se bloquea. –

Respuesta

2

La respuesta depende de algunos factores. ¿Tu programa se ejecuta dentro de un sistema operativo moderno?

En caso afirmativo, intentar acceder a un área de memoria que no está asignada provocará un SIGSEGV. Para lograr eso, debe usar una función específica del sistema para mapear la región de memoria que contiene esta dirección exacta antes de intentar acceder a ella.

+0

Está haciendo suposiciones de que esto se ejecuta en un sistema específico. Hasta donde yo sé, SIGSEGV es algo que solo sucede en los sistemas operativos basados ​​en POSIX. – Lundin

+1

No asumo un sistema operativo específico. Sin embargo, supongo que un sistema operativo moderno implementa la señalización POSIX, o al menos usa la misma terminología para su señalización, lo cual es cierto para Windows. Esa es la razón de la pregunta en la primera línea. – jweyrich

+0

http://en.wikipedia.org/wiki/List_of_real_time_operating_systems. Hay todo un mundo fuera de la rama de la programación de PC. – Lundin

12

El hecho de que haga esta pregunta indica que está por encima de su cabeza. Pero aquí van:

*(int *)0x12AED567 = 2345; 
+0

¿Lo has intentado? – jweyrich

+0

@jweyrich Sí. Lo ejecuté en la CPU ATMEGA32U4 en mi placa Teensy. Sin embargo, no hizo mucho. ¿Por qué preguntas? –

+0

Utilicé un 0 en lugar de una O mayúscula como el primer carácter del número hexadecimal en mi programa de prueba. ¿Es eso lo que te preocupa? –

1

Sólo tratar la posición de memoria como un puntero

int* pMemory = OX12AED567; 
*pMemory = 2345; 

Nota: Esto sólo funciona si esa ubicación de memoria es accesible y modificable por su programa. Escribir en una ubicación de memoria arbitraria como esta es inherentemente peligroso.

+0

Eso causaría un 'SIGSEGV' si esta región de memoria no está asignada. – jweyrich

+1

si la dirección no está en el rango de la memoria de proceso, ¿no se bloqueará? – Gopinath

+1

@Gopinath es dependiente de la implementación, pero en términos generales sí, se bloqueará. – JaredPar

0

Con la condición de que no es portátil o caja de seguridad (en absoluto):

*((int *)0x12AED567) = 2345; 
2

En lo que se refiere a C, que es un comportamiento indefinido. Mi siguiente sugerencia también es un comportamiento indefinido, pero evita todos los problemas basados ​​en tipos y alias: use caracteres.

int a = get_value(); 
char const * const p = (const char * const)&a; 
char * q = (char *)0x12345; 

memcpy(q, p, sizeof(int)); 

O bien, puede acceder a los bytes q[i] directamente. (Esta es la parte que es UB: el puntero q no se obtuvo como la dirección de un objeto real o como resultado de una función de asignación. A veces esto está bien, por ejemplo, si está escribiendo un programa independiente que se ejecuta en modo real y accede al hardware de gráficos, puede escribir en la memoria de gráficos directamente en una dirección conocida y codificada).

+2

Oh, vaya, vale. Se necesitará una modificación trivial, edición. –

0

Ha indicado que la dirección es física y que su código se está ejecutando en un proceso.

Así que si estás

  1. en una especie de sistema operativo de alto nivel, por ejemplo, Linux, tendrías que obtener una asignación en el espacio de direcciones físicas. En Linux,/dev/mem hace eso por usted.

  2. dentro del kernel o sin sistema operativo y con una MMU, debe traducir la dirección física a una dirección virtual. En el kernel de Linux, phys_to_virt() hace eso por ti. En el núcleo, supongo, esta dirección siempre se mapea.

  3. dentro del kernel o sin sistema operativo y sin MMU, escribe directamente en esa dirección. No hay mapeo para considerar en absoluto.

Ahora, tiene una asignación válida o la dirección física en sí, que pasa a su función.

void AssignValToPointer(uint32_t pointer, int value) 
{ 
    * ((volatile int *) pointer) = value; 
} 

Es posible que desee agregar la palabra clave volátil como el compilador podría optimizar la escritura operación de inmediato si usted no lee desde esa ubicación después (probablemente el caso cuando se escribe en un registro de un hardware de memoria mapeada).

Es posible que también desee utilizar el tipo de datos uintptr_t en lugar de uint32_t para el puntero.

1

C99 proyecto de norma

Ésta es probable que no es posible sin un comportamiento definido por la implementación.

Sobre lanza como:

*(uint32_t *)0x12AED567 = 2345; 

la C99 N1256 standard draft "6.3.2.3 Los punteros" dice:

5 Un entero puede convertirse en cualquier tipo de puntero. Excepto que se haya especificado anteriormente, el resultado está definido por la implementación, puede no estar alineado correctamente, podría no apuntar a una entidad del tipo al que se hace referencia, y podría ser una representación de captura. 56)

implementación GCC

documentos CCG su INT para aplicación puntero en: https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation

Un molde de número entero a puntero descarta bits más significativos si la representación puntero es más pequeño que el tipo entero, se extiende de acuerdo con la firma del tipo entero si la representación del puntero es mayor que el tipo entero, de lo contrario los bits no se modifican.

por lo que el molde funcionará como se esperaba para esta implementación. Espero que otros compiladores hagan cosas similares.

Cuestiones relacionadas