¿Por qué no se pueden pasar matrices como argumentos de función en C?

12

Después de este comentario , intenté buscar en Google por qué, pero mi google-fu falló.

Comentario del enlace:

[...] Pero lo importante es que las matrices y los punteros son cosas diferentes en C.

Suponiendo que no está utilizando ninguna extensión del compilador, generalmente no puede pasar una matriz a una función, pero puede pasar un puntero e indexar un puntero como si fuera una matriz.

Te estás quejando efectivamente de que los punteros no tienen una longitud adjunta. Debería quejarse de que las matrices no se pueden pasar como argumentos de función, o que las matrices se degradan a punteros implícitamente.

Florian Margaine
fuente
No estoy seguro de que sea la respuesta, pero parte del tipo de una matriz es su tamaño, por lo que creo que tendría que definir una función para cada tamaño que desee aceptar.
clcto
¿Quieres decir como punteros de función ? Por favor aclare la pregunta.
user949300
2
@ user949300 No, desde el contexto del comentario es bastante claro; no puede pasar una matriz a una función porque se convierte en un puntero, y él quiere saber por qué es así.
Doval
@DocBrown rlemon propuso una edición para esto.
Florian Margaine

Respuestas:

18

Mi primera suposición por la razón fue simplemente por razones de rendimiento y ahorro de memoria, y también por la facilidad de implementación del compilador (especialmente para el tipo de computadoras en el momento en que se inventó C). Pasar grandes matrices "por valor" parecía tener un gran impacto en la pila, necesita una operación de copia de matriz completa para cada llamada de función, y probablemente el compilador debe ser más inteligente para generar el código de ensamblaje correcto (aunque el último punto es discutible) . También sería más difícil tratar las matrices asignadas dinámicamente de la misma manera que las matrices asignadas estáticamente (desde el punto de vista de la sintaxis del lenguaje).

EDIT: después de leer algunas partes de este enlace , creo que la verdadera razón (y la razón por la cual las matrices de estructuras son tratados como los tipos de valor, mientras que las matrices únicos no lo son) es la compatibilidad con versiones anteriores de C a B predecesor . Aquí está la cita de Dennis Ritchie:

[...} La solución constituyó el salto crucial en la cadena evolutiva entre BCPL sin tipo y tipo C. Eliminó la materialización del puntero en el almacenamiento, y en su lugar causó la creación del puntero cuando el nombre de la matriz se menciona en una expresión. La regla, que sobrevive en la C de hoy, es que los valores del tipo de matriz se convierten, cuando aparecen en expresiones, en punteros al primero de los objetos que forman la matriz.

Esta invención permitió que la mayoría del código B existente continuara funcionando, a pesar del cambio subyacente en la semántica del lenguaje. [..]

Doc Brown
fuente
55
A struct Foo { int array[N]; } se puede pasar por valor. Y lo último sobre tratar las asignaciones dinámicas y estáticas de la misma manera parece sospechoso (una matriz en el sentido más estricto siempre incluye un tamaño, los conceptos unificadores para cosas como la indexación de matriz son punteros junto con la descomposición de matriz a puntero), ¿podría elaborar?
@delnan: Creo que los principios generales establecidos aquí son sólidos. Claramente, si ajusta su matriz en una estructura, está especificando su intención. En el caso general, casi siempre vas a pasar por referencia.
Robert Harvey
También encuentro el comentario al que se hace referencia en el OP innecesariamente pedante. Claramente, está pasando un puntero en lugar de una matriz por valor. Sin embargo, lo que es igualmente cierto es que efectivamente está pasando una matriz por referencia. Si la objeción es que no hay una longitud adjunta, también es bastante fácil pasar eso.
Robert Harvey
@RobertHarvey Eso sigue siendo una asimetría en el sistema de tipos: todo se pasa por valor, excepto los tipos de matriz (aunque las matrices que forman parte de un tipo de estructura se pasan por valor), e incluso utiliza la misma notación (ambas en el sitio de la llamada) y en la firma de la función).
@delnan: ¿Por qué es eso relevante, aparte de que tienes que recordarlo?
Robert Harvey
9

Una minicomputadora PDP con solo 8 kB de memoria no puede asignar una pila muy grande. Por lo tanto, en una máquina de este tipo, se debe tener cuidado en el diseño (o evolución) del lenguaje para poder minimizar lo que se necesita en la pila para el uso de llamadas de subrutina común esperado. C todavía se usa hoy para programar sistemas embebidos extremadamente limitados de memoria (unos pocos KB), por lo que la compensación suele ser buena.

En una arquitectura de procesador que tiene muy pocos registros, pasar cualquier matriz por puntero en lugar de por valor con mayor frecuencia permite que un registro se use como una optimización de llamada de subrutina.

hotpaw2
fuente
2
Tengo algunas placas que tienen 256 bytes de RAM para los datos y 2K EEPROM para el código. No desea hacer una copia de una matriz allí.
Jerry Jeremiah