Verbatim de linux’ man shmat
:
VALOR DEVUELTO
[…] en caso de error (void *) -1 se devuelve, y error se establece para indicar la causa del error.
(POSIX dice lo mismo usando un redacción ligeramente diferente.)
¿Existe alguna regla obligatoria o definición (¿estándar?) que (void *) -1
puede que no sea una dirección válida?
0xffffffff
es técnicamente una dirección válida en un entorno de 32 bits, pero en la mayoría de los sistemas operativos (ciertamente Linux/Windows) estará en la parte reservada del núcleo del espacio de direcciones. Eso significa que en los procesos de modo de usuario es seguro usarlo como un código de error ya que ninguna función de asignación de modo de usuario devolvería esto como una dirección utilizable.
Para simplificar, considere una máquina con 16 bits de espacio de direcciones. Esta máquina puede direccionar la memoria de 0 a 65535. En este caso (void*) -1
sería lo mismo que 0xffff, que es 65535. Si bien técnicamente esta dirección es válida, hay pocos sistemas que tendrían algo allí a lo que permitirían acceder.
La otra cosa a considerar es que casi todas las llamadas al sistema POSIX devuelven -1
en error
Como señaló Benj, en realidad es posible mapear la dirección NULL
. Esto se puede usar, por ejemplo, cuando desea ver si hay una asignación con un determinado shmid
en cuyo caso el shmaddr
el argumento se establece en NULL
y la funcion regresa NULL
para indicar que la memoria compartida existe.
Para responder a la pregunta directamente, no, no existe una regla, definición, norma o especificación obligatoria que diga (void *) -1
puede que no sea una dirección válida.
(Por supuesto, no hay reglas, definiciones, estándares o especificaciones sobre direcciones de memoria obligatorias. Veo gente caminando por la calle todos los días sin cumplir con el estándar C, por ejemplo, pero nunca he visto a nadie arrestado por eso. Pero, incluso si omitimos la parte obligatoria, usando (void *) -1
como dirección generalmente no está prohibido por las especificaciones comunes).
Sin embargo, no es necesario para (void *) -1
no ser una dirección válida para que shmat funcione. Solo es necesario que un exitoso llamar a shmat nunca regresa (void *) -1
y eso (void *) -1
ser compatible con el compilador con el fin de probar el valor de retorno de shmat. Si se cumplen estas dos condiciones, un programa siempre puede distinguir una llamada shmat exitosa de una llamada shmat fallida.
En cuanto a la segunda condición, la norma C no garantiza que (void *) -1
se puede usar, por lo que POSIX, al especificar que se trata de un retorno de error de shmat, requiere implícitamente la implementación de C (u otro lenguaje) para admitirlo. Entonces, esta es una extensión del lenguaje requerido por POSIX, y generalmente es algo simple de admitir para los compiladores.
Con respecto a la primera condición, considere cuándo podríamos querer que shmat regrese (void *) -1
para una llamada exitosa. shmat se puede llamar con una dirección solicitada por el usuario o sin ella, en cuyo caso la implementación elige una dirección. En cualquier arquitectura de computadora normal, hay múltiples razones para usar direcciones que son múltiplos de varios valores. Para shmat, el más obvio es el mapeo de memoria. En arquitecturas con memoria virtual, la memoria se asigna en unidades de páginas y shmat, cuando asigna memoria para el segmento, se asigna al inicio de una página. Cualquier tamaño de página par no tiene múltiplos que sean (void *) -1
ya que este último es impar, por lo que shmat nunca elige asignar un segmento a (void *) -1
. Incluso si shmat no usara el tamaño de página, normalmente usaría alguna otra alineación, como 4, 8 o 16 bytes, porque proporcionar memoria alineada significa que las estructuras almacenadas al comienzo de esa memoria se alinearán, lo que da como resultado una memoria más rápida. acceso en muchos procesadores.
Eso deja el caso donde el usuario solicita (void *) -1
como dirección. Esto sería inusual y podría funcionar solo si el segmento de memoria fuera un solo byte o si el modelo de memoria permitiera ajustarse (o si el compilador presentara un modelo de memoria muy extraño en el que (void *) -1
no eran el último byte en el espacio de direcciones). No puedo decir con certeza si algún sistema POSIX admite esto o no. Sin embargo, está claro que esto es esencialmente inútil, y nadie tiene otra razón para hacerlo que no sea la curiosidad. Por lo tanto, es seguro y razonable descartar este caso de shmat, simplemente diciendo que no se admite, no lo haga.