retorno - parametros formales en c
¿Cómo aceptan algunas funciones C los parámetros nulos? (4)
Siempre pensé que C no acepta parámetros NULL, hasta que comencé a aprender sobre punteros. En algunos lenguajes de programación, como python para uno, es posible pasar un parámetro NULL como argumento, pero en CI siempre pensé que esto daría como resultado un comportamiento indefinido .
Mi pregunta es solo de curiosidad, ¿cómo puede una función, como esta ...
waitpid(child_pid, &status, options); //pointer &status
... acepta un puntero NULL como parámetro sin ejecutar Undefined Behavior , no los punteros NULL simplemente apuntan a nada?
En pocas palabras, ¿por qué es esto aceptable en C?
En algunos lenguajes de programación [...] es posible pasar un parámetro NULL como argumento, pero en CI siempre pensé que esto daría como resultado un comportamiento indefinido.
Pasar un parámetro NULL
para un puntero por sí mismo no da como resultado UB; está intentando acceder a la memoria apuntada por un puntero establecido en NULL
que sí lo hace.
Pasar NULL
es una práctica muy común para situaciones donde algo no está especificado. Se espera que el llamante verifique los parámetros para NULL
antes de realizar el acceso. Por ejemplo, el estándar le permite pasar NULL
a free
, lo que hace que la función sea mucho más conveniente.
¿los apuntadores
NULL
simplemente apuntan a nada?
Ellos si. Pero ese "nada" es bien conocido a nivel mundial, por lo que usar un NULL
permite comunicar el hecho de que un puntero apunta a nada a las funciones que usted llama. En otras palabras, el cheque
if (myPointer == NULL)
está bien definido * , por lo que puede usarlo para su ventaja.
* A menos que use un puntero colgante, es decir, un puntero que haya liberado, o un puntero que apunte al objeto que salió del alcance. Puede evitar que ocurra la primera situación asignando NULL
a cada puntero que free()
, y la segunda situación al declarar punteros en el alcance que tiene el mismo o mayor nivel de anidación que el alcance de un objeto automático al que apunta el puntero está apuntando.
Porque una función puede verificar si el puntero es NULL y evitar usarlo. Un ejemplo clásico es una función que devuelve algo como un valor de retorno, y puede proporcionar cierta información adicional a través de un parámetro de puntero. Si la persona que llama no está interesada en dicha información (y el destinatario está preparado para esto), el parámetro del puntero se establece en NULL, y la función llamada no intentará almacenar nada en la ubicación que señala.
int divide(int dividend, int divisor, int *remainder=NULL)
{
if(remainder!=NULL)
*remainder=dividend%divisor;
return dividend/divisor;
}
waitpid sigue este modismo: si no te importa el estado, puedes pasar NULL, evitando una variable ficticia.
En general, puede usar NULL como un valor especial para indicar que no se ha pasado ningún puntero válido; otro uso común es decir "usar un valor predeterminado" para algún parámetro de puntero.
Tenga en cuenta que esto no es muy diferente de Python: no puede hacer mucho en una None sin obtener un error, pero siempre puede verificar si un valor es None y actuar en consecuencia.
Todo depende de cómo manejes NULL. Esencialmente NULL representa un valor de 0, por lo tanto, si intenta usarlo como un entero, no debería tener ningún problema. ¡PERO tenga en cuenta que NULL es una definición para representar la posición de memoria no válida (inexistente) y no debe usarse como un entero!
Para los punteros, por otro lado, es importante verificar si el puntero apunta a una dirección válida. Por lo general, las funciones que aceptan punteros deben verificar si el valor pasado es válido; de lo contrario, terminará intentando acceder a una posición de memoria no válida y bloquearse.
void func_with_optional_arg(char *optional)
{
if (optional == NULL) {
// do something differently
}
/* ... */
}
¿Por qué eso invocaría a UB? Desreferenciando un puntero NULL
ciertamente lo haría, pero pasar uno no lo hace. NULL
es un valor centinela utilizado para determinar si un puntero es válido (no que los punteros no válidos no pueden tener otros valores, pero usamos este explícitamente). Si lo pasa a una función invocada por UB, ¿cuál sería el sentido de su existencia? ¿en primer lugar?
mientras que pasar un valor NULL no puntero no es?
No existe un "NULL no puntero" en C, así que no estoy seguro de lo que quiere decir aquí.