¿Existe algo como un unsigned int*
que es diferente de int*
. Yo sé eso unsigned
tiene un mayor rango de valores. Aún así, no puedo int*
incluso señalar a cualquiera unsigned int
?
ouah
int *
y unsigned int *
son dos tipos de punteros diferentes que no son tipos compatibles. También son punteros a tipos incompatibles. Para la definición de tipos compatiblespor favor refiérase a § 6.2.7 en la Norma C (C11).
Ser punteros a tipos incompatibles significa que, por ejemplo, esto:
unsigned int a = 42;
int *p = &a; // &a is of type unsigned int *
no es válido (se violan las restricciones del operador de asignación).
Otra diferencia entre los dos tipos es que para la mayoría de los otros tipos de punteros (aunque es poco probable aquí) C no garantiza que tengan el mismo tamaño o la misma representación.
-
Cortejar. La pregunta es “¿Hay algo como un int* sin firmar que sea diferente de int*”, los votantes negativos digan qué es lo que está mal en mi respuesta.
– ouah
23 de diciembre de 2014 a las 18:03
-
No veo nada malo en esta respuesta. Además, si no te atreves a comentar, entonces no bajes el voto, por favor.
– trucos
23 de diciembre de 2014 a las 18:05
-
@Namfuak no es válido desde el punto de vista de C. Se violan las restricciones del operador de asignación. Se requiere un diagnóstico y un compilador es libre de negarse a traducir el programa.
– ouah
23 de diciembre de 2014 a las 21:23
-
Este código es una violación de restricción, sin embargo
int *p = (int *)&a
es válida. Su respuesta solo aborda si se requiere un elenco para la compilación, mientras que me parece que OP estaba preguntando qué sucede en el tiempo de ejecución si se incluye el elenco.–MM
23 de diciembre de 2014 a las 23:41
-
@MattMcNabb Eso contradice directamente el propio consejo de SE. Votar negativamente un comentario con “Considere agregar un comentario si cree que esta publicación se puede mejorar”.
– usuario820304
24 de diciembre de 2014 a las 0:41
2501
El estándar C define el uso de un puntero sin firmar para apuntar a una versión firmada del mismo tipo.
Por lo tanto, interpretar un int a través de un puntero int sin signo y viceversa es válido.
ISO/IEC 9899:201x 6.5 Expresiones, p7:
Un objeto tendrá acceso a su valor almacenado solo mediante una expresión lvalue que tenga uno de los siguientes tipos: 88)
— un tipo que es el tipo firmado o no firmado correspondiente al tipo efectivo del objeto,
— un tipo que es el tipo firmado o no firmado correspondiente a una versión calificada del tipo efectivo del objeto,
88) La intención de esta lista es especificar aquellas circunstancias en las que un objeto puede o no ser alias.
El tipo efectivo es básicamente el tipo del objeto:
El tipo efectivo de un objeto para acceder a su valor almacenado es el tipo declarado del objeto, si lo hay.
Se ha planteado una cuestión sobre la interpretación de la regla anterior. La siguiente es mi justificación adicional al respecto.
Este texto a continuación se enumera únicamente por razonamiento semántico de la palabra: correspondiente, y no por las reglas directas que especifica.
6.2.5 Tipos
p6: Para cada uno de los tipos enteros con signo, hay un correspondiente (pero diferente) tipo entero sin signo (designado con la palabra clave unsigned) que utiliza la misma cantidad de almacenamiento (incluida la información de signo) y tiene los mismos requisitos de alineación.
p9: El rango de valores no negativos de un tipo entero con signo es un subrango del
correspondiente tipo entero sin signo, y la representación del mismo valor en cada tipo es la misma.41)p12: Para cada tipo flotante hay un correspondiente tipo real, que siempre es un tipo flotante real. Para tipos flotantes reales, es el mismo tipo. Para tipos complejos, es el tipo dado al eliminar la palabra clave _Complex del nombre del tipo.
p27: Además, existe el calificador _Atomic. La presencia del calificador _Atomic designa un tipo atómico. El tamaño, la representación y la alineación de un tipo atómico no necesitan ser los mismos que los del correspondiente tipo no calificado
6.2.6.2 Tipos enteros
p2: Para tipos enteros con signo, los bits de la representación del objeto se dividirán en tres grupos: bits de valor, bits de relleno y el bit de signo. No es necesario que haya partes de relleno; El carácter firmado no tendrá bits de relleno. Habrá exactamente un bit de signo. Cada bit que sea un bit de valor tendrá el mismo valor que el mismo bit en la representación de objeto del correspondiente tipo sin firmar
p5: Los valores de cualquier bit de relleno no están especificados. 54) Una representación de objeto válida (sin captura) de un tipo de entero con signo donde el bit de signo es cero es una representación de objeto válida del tipo sin signo correspondiente y representará el mismo valor .
(Y muchos más ejemplos con uso idéntico de la palabra correspondiente)
Como puede ver en los fragmentos anteriores, Estándar usa la palabra correspondiente para referirse a diferentes tipos o tipos con diferentes especificadores y/o calificadores. Por lo tanto, como se ve en los ejemplos anteriores, Standard usa la palabra como se usaría en este ejemplo: tipo calificado es correspondiente a escribe.
Sería ilógico usar repentinamente la palabra correspondiente para un propósito diferente: referirse a tipos calificados/especificados completamente idénticos e incluso confundir más las cosas al incluir las palabras firmado y sin firmar en la misma oración sin una buena razón.
La intención del 6.5, p7 es: a type that is the signed or unsigned type
ya sea un tipo firmado o sin firmar corresponding to the effective type of the object
que, de lo contrario, coincide (corresponde) con el tipo de destino. Entonces, por ejemplo: tipo efectivo es: int, int o int sin signo corresponden a ese tipo.
-
Lo dices en serio
int *
yunsigned int *
se pueden usar indistintamente sin yeso?– Gamal Othman
11/03/2019 a las 11:00
milímetro
unsigned int *
y int *
son de diferentes tipos. Para convertir uno al otro debe usar un yeso.
Si lee un valor a través de un puntero, intenta interpretar los bits almacenados en esa ubicación de memoria como si fueran bits del tipo al que apunta el puntero que está leyendo.
Si los bits en esa ubicación de memoria no fueron escritos por un puntero del mismo tipo que está leyendo, entonces esto se llama alias.
La regla estricta de creación de alias especifica qué tipos pueden tener o no alias; alasing entre un tipo de signed
y unsigned
siempre se permiten versiones.
Sin embargo, si los bits no son una representación válida de un valor en el tipo que está leyendo, provoca un comportamiento indefinido.
En los sistemas modernos no existen tales representaciones de “trampa”, por lo que no tiene ningún problema. Pero digamos que estabas en un sistema de complemento a 1 que quedó atrapado en cero negativo:
unsigned int x = 0xFFFFFFFF;
int *y = (int *)&x;
printf("%d\n", y);
El intento de leer y
podría causar una falla de hardware o cualquier otro comportamiento.
-
Entonces aparentemente gcc y clang permitir esta asignación sin un reparto como una extensión Aunque yo no puedo decir que el razonamiento detrás de la extensión sea bueno
– Shafik Yaghmour
29 de enero de 2018 a las 5:57
-
@ShafikYaghmour Imprimen un diagnóstico, por lo que cumplen con el estándar; el punto conflictivo es que el diagnóstico predeterminado es “advertencia” en lugar de “error”
–MM
29 de enero de 2018 a las 8:27
-
Admito que aprovecho las extensiones del compilador para usar
char *
,unsigned char *
indistintamente, es molesto cuando se trabaja con búferes de texto y datos binarios mixtos–MM
29 de enero de 2018 a las 8:29
Arjun Sreedharan
el valor de la puntero es lo mismo, pero son de diferentes tipos. Surgirá una diferencia dependiendo de la forma en que interprete el puntero, por ejemplo: desreferenciación.
unsigned int *u;
int *d;
unsigned int v = 2147483648; /* 2^31 */
u = &v;
d = (int*) &v;
printf("%u\n", *u);
printf("%d\n", *d);
dará salida:
2147483648
-2147483648
La diferencia en la salida surge porque en printf("%d\n", *d)
, d
se elimina la referencia y se imprime como si apuntara a un signed int
, excepto que no lo es. Por lo tanto, debe mantener una distinción entre los 2 tipos de punteros en su código.
Puede apuntar ya que ambos tienen el mismo tamaño. El problema es que esto introducirá un error difícil de encontrar, porque interpretará un valor con signo como sin signo o viceversa.
jim mcnamara
Un puntero es un número que es una dirección de memoria. Por lo tanto, los punteros deben tener suficiente precisión para poder abordar toda la memoria para la implementación.
Ya sea que haga referencia a un int con o sin signo, no hay diferencia en la estructura interna del puntero porque, en teoría, el int o el int sin signo podrían estar casi en cualquier parte de la memoria. El tipo de datos (sin firmar) debe declararse para “ayudar” al compilador a decidir si el código es correcto.
Un puntero apunta a bits. El tipo del puntero le informa a cuántos bits se hace referencia y qué “significan”. Los bits, en ausencia de esa información, no tienen sentido.
– Lame caliente
23 de diciembre de 2014 a las 17:41
@HotLicks: un puntero apunta a un objeto de un tipo específico.
–Keith Thompson
23 de diciembre de 2014 a las 17:52
@KeithThompson: un puntero especifica el tipo. Tal vez de una manera correcta, tal vez no.
– Lame caliente
23/12/2014 a las 18:00
El “tipo” de un puntero le dice al compilador qué tipo de datos esperar en esa dirección cuando elimina la referencia o hace cálculos de puntero. Pero en realidad no es más que una dirección. Después de todo, no hay forma de que sepa qué significan los bits aleatorios en alguna dirección aleatoria a menos que usted se lo diga.
– Lee Daniel Crocker
23 de diciembre de 2014 a las 18:07
Es interesante ver que hay 3 respuestas mejor calificadas que la aceptada. Sería interesante conocer los pensamientos de OP sobre la selección.
– chux – Reincorporar a Monica
24 de diciembre de 2014 a las 15:59