2010-02-22 12 views
10

La gramática ANSI C de -link- dame las siguientes normas para las declaraciones de matriz:ANSI-C gramática - declaraciones de arrays como [*] et alii

(1) | direct_declarator '[' type_qualifier_list assignment_expression ']' 
(2) | direct_declarator '[' type_qualifier_list ']' 
(3) | direct_declarator '[' assignment_expression ']' 
(4) | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' 
(5) | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' 
(6) | direct_declarator '[' type_qualifier_list '*' ']' 
(7) | direct_declarator '[' '*' ']' 
(8) | direct_declarator '[' ']' 

Ahora tengo algunas preguntas sobre éstas:

  • ¿Puedo usar (1) - (6) excepto (3) solo en C99?
  • ¿Qué son (4) y (5) para? La palabra clave "estática" me confunde.
  • ¿Dónde se usa (6)?
  • ¿Cuál es la diferencia entre los dos prototipos de las funciones siguientes:

    void foo(int [*]); y

    void foo(int []);

Gracias.

Respuesta

15

No se pueden usar calificadores de tipo static en la porción de tamaño de la declaración de matriz en C89/90. Estas características son específicas de C99.

static de declaración de matriz indica al compilador que prometes que el número especificado de elementos siempre estará presente en la matriz pasada como argumento real. Esto podría ayudar a los compiladores a generar un código más eficiente. Si infringe su promesa en el código real (es decir, pasa una matriz más pequeña), el comportamiento no está definido. Por ejemplo,

void foo(int a[static 3]) { 
    ... 
} 

int main() { 
    int a[4], b[2]; 
    foo(a); /* OK */ 
    foo(b); /* Undefined behavior */ 
} 

El * en tamaño de la porción de declaración de matriz se usa en sólo declaraciones función prototipo.Indica que la matriz tiene una longitud variable (VLA). Por ejemplo, en la definición de función se puede utilizar un VLA con un tamaño concreto de tiempo de ejecución

void foo(int n, int a[n]) /* `a` is VLA because `n` is not a constant */ 
{ 
    ... 
} 

Cuando se declara el prototipo se puede hacer lo mismo

void foo(int n, int a[n]); /* `a` is VLA because `n` is not a constant */ 

pero si no se especifica los nombres de los parámetros (lo cual está bien en el prototipo), no puede usar n como tamaño de matriz, por supuesto. Sin embargo, si usted todavía tiene que decirle al compilador que la matriz va a ser un VLA, se puede utilizar el * para ese propósito

void foo(int, int a[*]); /* `a` is VLA because size is `*` */ 

Tenga en cuenta, que el ejemplo con una matriz 1D no es una buena idea. Incluso si se omite el * y declara la función anterior como

void foo(int, int a[]); 

entonces el código todavía no tendrán ningún problema, ya que en función de tipo de declaraciones de parámetros matriz está implícita sustituido por un tipo de puntero de todos modos. Pero una vez que comienzas a utilizar matrices multidimensionales, el uso adecuado de * se vuelve importante. Por ejemplo, si la función se define como

void bar(int n, int m[n][n]) { /* 2D VLA */ 
    ... 
} 

el prototipo podría tener el siguiente

void bar(int n, int m[n][n]); /* 2D VLA */ 

o como

void bar(int, int m[*][*]); /* 2d VLA */ 

En este último caso, la primera * se puede omitir (debido al reemplazo de matriz a puntero), pero no al segundo *.

+0

Supongo que el lugar donde esto realmente importa es cuando haces 'f (int, int, a [*] [*])' o algo por el estilo ... – dmckee

+0

@dmckee: Estaba simplemente agregando eso a mi respuesta :) – AnT

+0

Mucha gente pensando en las mismas líneas por aquí. Grandes mentes y todo eso ... – dmckee

0

Mi K & R2nd (que cubre e incluye el estándar ANSI) no parece decir nada sobre [*] ni en el texto ni en el estándar en sí. Tampoco puedo hacer que la gramática oficial en el estándar acepte esa sintaxis.

Puede estar relacionado con K & R c (aunque no lo recuerdo), puede haber sido una extensión común, o ha sido una propuesta que en última instancia no fue estándar.

Supongo supongo hace que las dimensiones de la matriz explícitamente no especificadas. Pero solo estoy adivinando.


Hmm ... gcc acepta

#include <stdio.h> 

void f(int s, int a[*]); 

int main(void){ 
    int a[2] = {0}; 
    f(2,a); 
    return 0; 
} 

void f(int s, int a[]){ 
    int i; 
    for (i=0; i<s; ++i){ 
    printf("%d\n",a[i]); 
    } 
} 

en ANSI, el modo de C89 y C99; no emitiendo advertencias, incluso con -Wall. Tenga en cuenta que no le gustó la sintaxis [*] en la definición de la función. Al agregar -pedantic, se quejó de la sintaxis [*] en los modos c89 y ansi, pero continuó aceptando en el modo c99.

+0

-Wall no emitirá advertencias para toda la sintaxis que en C89 se trata como una extensión de GNU. Creo que también necesitarás -pedante para eso. K & R 2nd ed. fue escrito contra el estándar ANSI C89 (ahora ISO C90), por lo que no incluirá la gramática C99. C99 agrega matrices de longitud variable y otra sintaxis relacionada con matrices. – Clifford

+0

En cuanto a no me gusta el [*] en la definición de función, el estándar dice [*] "es un tipo de matriz de longitud variable de tamaño no especificado, que solo se puede usar en declaraciones con * función prototipo * alcance" – Clifford

1

Espero que no intente aprender gramática C a partir de una especificación yacc? El enlace que publicó parece estar basado en the ISO C99 draft. La sección relevante es 6.7.5.2. La redacción es arcana (¡pero menos que la sintaxis yacc!)

+0

No, yo ' m no aprendiendo C con eso ;-) – tur1ng

+0

@ tur1ng: Es solo que dijiste "La gramática ANSI C de -link- da * me * las siguientes reglas para las declaraciones de matriz". Sugiero que esas reglas fueron pensadas para el consumo de yacc, no para el consumo humano, y que el estándar ISO está destinado a humanos (y es el documento fuente para el yacc). Y dije "Gramática C" en lugar de solo "C"; puedes aprender C a un nivel de trabajo sin un conocimiento complejo de la gramática. ¿Quizás estás escribiendo un compilador o un analizador estático? – Clifford

+0

Oh, lo siento, estaba leyendo demasiado rápido. Sí, es para un analizador estático. – tur1ng