2009-11-06 28 views
7

en c, intenté imprimir la dirección de la variable y la dirección de alguna función. Tengo uno es un valor negativo, el otro es un valor positivo. Mi pregunta es: ¿por qué C no representa en todos los valores negativos o todos positivos?dirección de memoria valor positivo o negativo en c?

Aquí está mi código:

int foo() { 
    return 0; 
} 

int main() { 

    int a; 
    printf("%d\n",&a); 

    printf("%d\n",foo); 

    return 0; 
} 

Aquí es resultado:

-1075908992 134513684 

Respuesta

29

Las direcciones de memoria no deben ser interpretados como enteros con signo de ese modo. El signo del número depende del conjunto de bits más alto (suponiendo la representación complementaria de dos, que es utilizada por la gran mayoría de los sistemas actualmente en uso), por lo que una dirección de memoria superior a 0x80000000 en un sistema de 32 bits será negativa y una memoria la dirección debajo de 0x80000000 será positiva. No hay un significado real para eso.

Debe estar imprimiendo direcciones de memoria utilizando el modificador %p; alternativamente, algunas personas usan %08x para imprimir direcciones de memoria (o %016llx en sistemas de 64 bits). Esto siempre se imprimirá como un entero sin signo en hexadecimal, que es mucho más útil que un entero decimal con signo.

int a; 
printf("%p\n", &a); 
+2

'% 08x' es no portátil (y en realidad sería mal estado en una plataforma LLP64, por ejemplo) . –

+2

Sí, es por eso que debe usar '% p', pero vale la pena mencionar que mucha gente usa'% 08x' en máquinas de 32 bits. El 99% del tiempo, si está imprimiendo un valor de puntero, está depurando algo, para que sepa exactamente en qué arquitectura se está ejecutando. –

6

debe pasar al formateador puntero:

printf("%p\n",foo); 
3

Ni un puntero tiene signo, pero cuando se convierte en un entero con signo puede ser positivo o negativo.

Por cierto, que pasa un puntero a una variable printf con formato diseñado para imprimir un entero provoca un comportamiento indefinido. Siempre debe convertir explícitamente al tipo correcto para obtener un comportamiento no especificado o definido por la implementación (dependiendo del modelo).

+0

Derecha; eso podría causar problemas reales en un sistema donde los punteros y las entradas no eran del mismo tamaño (como la mayoría de los sistemas de 64 bits). –

4

Usted está imprimiendo en decimal. Probablemente desee imprimir la ubicación de la memoria en hexadecimal (usando "% p") (la mayoría de las direcciones de memoria se muestran en hexadecimal por convención).

0

utilizar el siguiente código:

printf("%u",&a); 
+0

Esto es incorrecto. % u es para entradas sin firmar, no para punteros. – ChrisInEdmonton

+1

me gusta esta idea. obliga a la dirección a ser positiva. – root

1

También es posible usar printf("%p", &a) también. %p es el especificador de formato de puntero para generar el valor de un puntero de una manera definida por la implementación. En términos prácticos, es prácticamente lo mismo que% x, pero manejaría el caso en que un puntero es más grande que un int.

+0

Buen punto. Sin embargo, tienes que tener un compilador reciente para que esto funcione. (No te rías, tengo que usar compiladores de décadas deprimentemente) –

7

Para ser lo más estándar posible, pase "% p" en el formato de cadena a printf() y eche el argumento a void*.

printf("%p\n", (void*)&a); 
printf("%p\n", (void*)foo); 

Cita del Proyecto de Norma (n1401.pdf)

 
    7.20.6.1 The fprintf function 

8 The conversion specifiers and their meanings are: 

p  The argument shall be a pointer to void. The value of the pointer 
     is converted to a sequence of printing characters, in an 
     implementation-defined manner. 
+2

Sugiero seguir tus propios consejos y reemplazar '% d' con'% p' en el código de ejemplo – Christoph

+0

+1 por mencionar el molde en ' void * 'como promoción de argumento predeterminada no implica ninguna conversión de puntero, es decir, obtendrá un comportamiento indefinido en las plataformas donde los punteros a diferentes tipos tienen representaciones diferentes – Christoph

0

printf no es una herramienta de interpretación mágica. Todo lo que está haciendo si le das "% d" te muestra el aspecto del patrón de bits que se encuentra en esa variable como un entero.

cuanto a por qué algunos indicadores son negativos y algunos positivos, todo lo que significa es que algunos tienen el bit de orden establecido y algunos no lo hacen.Las direcciones que se le dan a los objetos es realmente solo el negocio de su sistema operativo (generalmente con algo de ayuda de hardware). El lenguaje de programación no tiene voz ni voto.

Si yo fuera usted, no estaría imprimiendo direcciones de esa manera. Si realmente sientes la necesidad de mirarlos, usa "% x" en lugar de "% d". Eso los imprimirá en hexadecimal, lo que hace que sea mucho más fácil averiguar qué bits están encendidos y cuáles no. Por lo general, todo lo que le interesarán con las direcciones es si son 0 o no, y si coinciden con el valor de alguna otra dirección.

3

Los punteros no son enteros con signo, ya que se parecen mucho más a enteros sin signo. Sin embargo, los está imprimiendo como si fueran enteros con signo. En un sistema de 32 bits, hay varias cosas que probablemente tengan 32 bits de longitud: int, unsigned int, float y punteros. En general, no se puede decir cuáles son simplemente mirándolos, pero todos significan cosas diferentes. (Como experimento, puede pasar varios enteros e imprimirlos como flotadores y viceversa: es una mala práctica en general, pero puede mostrarle que diferentes tipos de datos significan cosas diferentes.)

Funciones que toman un número variable de argumentos (funciones "variadic") lo hacen de una manera complicada. En particular, no verifican los tipos de argumentos. Puede pasar cualquier argumento que desee al printf() y funciones similares, pero lograr que estén de acuerdo con el especificador de formato es su problema. Esto significa que la función no tiene forma de obtener el tipo correcto (como lo haría si pasara un float a una función como int foo(int)).

Pasar los tipos de argumentos incorrectos conduce a un comportamiento indefinido, y es particularmente probable que genere problemas si pasa argumentos del tamaño incorrecto. En la mayoría de los sistemas de 64 bits, los punteros son 64 bits y int s son 32.

Por lo tanto, debe usar lo correcto en la cadena de formato. printf("%p", &a); imprimirá la dirección de a como un puntero, que es lo que desea. El estándar requiere algo como printf("%p", (void *)&a);, pero como una cuestión práctica que es innecesaria en cualquier computadora es probable que encuentre.

0

Además del uso de %p, también puede convertir a uintptr_t para asegurarse de obtener un entero sin formato.

Uso PRIuPTR (o PRIXPTR para hexadecimal) forma <inttypes.h> para obtener el especificador de formato correcto:

printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo); 
Cuestiones relacionadas