c++ - example - ¿Por qué se define el valor de retorno de la implementación malloc(0)?
malloc en c++> (3)
ISO / CEI 9899: TC2 (es decir, el estándar C99), §7.20.3 establece:
Si el tamaño del espacio solicitado es cero, el comportamiento está definido por la implementación: se devuelve un puntero nulo o el comportamiento es como si el tamaño fuera un valor distinto de cero, excepto que el puntero devuelto no se debe usar para acceder a un objeto .
En otras palabras, malloc (0) puede devolver NULL o un puntero válido que no puedo desreferenciar.
¿Cuál es la razón de este comportamiento?
¿Y no sería más fácil definir que malloc (0) conduce a UB?
Debido a que la asignación de 0 bytes puede tener sentido. Por ejemplo, cuando está asignando una matriz con un número desconocido de elementos. UB permitiría la falla del programa, mientras que con el comportamiento actual puede asignar con seguridad numberOfItems * itemSize
bytes.
La lógica es la siguiente: si pide 0 bytes, obtiene un puntero hacia atrás. Por supuesto, no debe desreferenciarlo, ya que esto habría accedido al octeto 0 (que no ha asignado). Pero puedes liberar la memoria de forma segura después. Entonces no necesitas hacer 0 un caso especial.
Esto fue por qué no definir malloc(0)
como UB. Acerca de la decisión de no definir el resultado estrictamente ( NULL
vs. único puntero al espacio vacío) ver la respuesta de James. (En resumen: ambos enfoques tienen sus ventajas y desventajas. La idea de devolver un puntero único no nulo es más convincente, pero requiere más trabajo conceptual y pone más carga a los implementadores).
El C99 Rationale (enlace PDF) analiza las funciones de gestión de memoria (de C99 7.20.3) y explica:
El tratamiento de punteros nulos y solicitudes de asignación de longitud cero en la definición de estas funciones se guió en parte por el deseo de apoyar este paradigma:
OBJ * p; // pointer to a variable list of OBJs /* initial allocation */ p = (OBJ *) calloc(0, sizeof(OBJ)); /* ... */ /* reallocations until size settles */ while(1) { p = (OBJ *) realloc((void *)p, c * sizeof(OBJ)); /* change value of c or break out of loop */ }
Se ha informado que este estilo de codificación, que el Comité no respalda necesariamente, tiene un uso generalizado.
Algunas implementaciones han devuelto valores no nulos para solicitudes de asignación de cero bytes.
Aunque esta estrategia tiene la ventaja teórica de distinguir entre "nada" y "cero" (un puntero no asignado frente a un puntero al espacio de longitud cero), tiene la desventaja teórica más convincente de requerir el concepto de un objeto de longitud cero.Dado que no se puede declarar la Biblioteca de objetos, la única forma en que podrían existir sería a través de dichas solicitudes de asignación.
El Comité C89 decidió no aceptar la idea de objetos de longitud cero. Por lo tanto, las funciones de asignación pueden devolver un puntero nulo para una solicitud de asignación de cero bytes. Tenga en cuenta que este tratamiento no excluye el paradigma descrito anteriormente.
CAMBIO TRANQUILO EN C89 : un programa que se basa en solicitudes de asignación de tamaño cero que devuelven un puntero no nulo se comportará de manera diferente.
Hacer que malloc(0)
resulte en UB sería mucho peor. Tal como están las cosas, no tiene que importarle lo que sucede cuando el tamaño es cero, siempre que sea coherente con las llamadas free
.
El problema es que algunas implementaciones existentes asignan un puntero a malloc(0)
, algunas devuelven punteros nulos y casi todas se mantienen fieles a su comportamiento porque las mismas personas que escribieron las implementaciones escribieron muchos programas malos no portátiles. que hace uso de su comportamiento elegido (GNU es uno de los peores delincuentes en esta área). Por lo tanto, el estándar se atascó permitiendo ambos comportamientos para mantenerlos a todos contentos.