c void-pointers

¿Es((void*)-1) una dirección válida?



void-pointers (3)

Para responder directamente a la pregunta, no, no hay una regla, definición, estándar o especificación obligatoria que diga (void *) -1 que no sea una dirección válida.

(Por supuesto, no hay reglas, definiciones, estándares o especificaciones sobre las direcciones de memoria que sean obligatorias. Veo a personas que caminan por la calle todos los días sin cumplir con el estándar C, por ejemplo, pero nunca he visto a nadie arrestado por ello. Pero, incluso si omitimos la parte obligatoria, el uso de (void *) -1 como una dirección generalmente no está prohibido por especificaciones comunes.)

Sin embargo, no es necesario que (void *) -1 no sea una dirección válida para que funcione shmat. Es simplemente necesario que una llamada exitosa a shmat nunca devuelva (void *) -1 y que (void *) -1 sea ​​compatible con el compilador para probar el valor de retorno de shmat. Si se cumplen estas dos condiciones, entonces un programa siempre puede distinguir una llamada shmat exitosa de una llamada shmat no exitosa.

Con respecto a la segunda condición, el estándar C no garantiza que se pueda usar (void *) -1 , por lo que POSIX, al especificar que se trata de una devolución de error de shmat, implícitamente requiere la implementación de C (u otro lenguaje) para admitirla. Así que esta es una extensión del lenguaje requerido por POSIX, y generalmente es una cosa simple para que los compiladores la soporten.

Con respecto a la primera condición, considere cuándo podríamos desear que shmat regrese (void *) -1 para una llamada exitosa. Se puede llamar a shmat 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 varias razones para usar direcciones que son múltiplos de varios valores. Para shmat, el más obvio es el mapeo de memoria. En las arquitecturas con memoria virtual, la memoria se asigna en unidades de páginas, y shmat, cuando asigna la memoria para el segmento, se asigna al inicio de una página. Cualquier tamaño de página uniforme 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 la 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 inicio de esa memoria estarán alineadas, lo que resulta en una memoria más rápida Acceso en muchos procesadores.

Eso deja el caso donde el usuario solicita (void *) -1 como una dirección. Esto sería inusual, y podría funcionar solo si el segmento de memoria fuera de un solo byte o si el modelo de memoria permitiera el ajuste (o el compilador presentara un modelo de memoria muy extraño en el que (void *) -1 no fuera el último byte en el espacio de dirección). No puedo decir con seguridad si algún sistema POSIX soporta 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 es compatible, no lo haga.

Verbatim de Linux '' man shmat :

VALOR DEVUELTO

[...] en error (void *) -1 se devuelve, y errno se configura para indicar la causa del error.

(POSIX dice lo mismo usando una redacción ligeramente diferente .)

¿Hay alguna regla o definición obligatoria (estándar?) Que (void *) -1 no sea una dirección válida?


Por simplicidad, 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 el mismo que 0xffff, que es 65535. Si bien técnicamente esta dirección es válida, hay pocos sistemas que tendrían algo allí que permitieran ser accedido

La otra cosa a considerar es que casi todas las llamadas al sistema POSIX devuelven -1 en caso de error.

Como señaló Benj, en realidad es posible asignar la dirección NULL . Esto se puede usar, por ejemplo, cuando desea ver si hay una asignación con un shmid especificado, en cuyo caso el argumento shmaddr se establece en NULL y la función devuelve NULL para indicar que existe la memoria compartida.


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 kernel 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 lo devolvería como una dirección utilizable.