2012-06-06 5 views
14

¿Hay alguna manera de que pueda añadir const palabra clave a un arreglo pasado como parámetro a la función:Adición palabra clave const a una matriz pasada como parámetro para funcionar

void foo(char arr_arg[]) 

Si coloco const antes char (void foo(const char arr_arg[])) o después de char (void foo(char const arr_arg[])), eso significaría que es char que es constante, no el arr_arg.

yo acabamos de read que bajo el capó una matriz enviado como parámetro a la función se representa como un puntero, así void foo(char arr_arg[]) es la misma que void foo(char* ptr_arg). Teniéndolo en cuenta, puedo volver a escribir la función como void foo(char * const ptr_arg) para que sea exactamente lo que quiero lograr.

Pero me gustaría saber si hay una manera de añadir const palabra clave en esta declaración void foo(char arr_arg[]) para que sea el mismo que void foo(char * const ptr_arg) (y no void foo(char const * ptr_arg) o void foo(const char * ptr_arg))?

Solo quiero entender si hay una sintaxis para hacer que arr_arg sea constante con la notación de matriz [].

+4

¿hay alguna razón específica no desea hacer 'void foo (const char * ptr_arg)'? Es exactamente la misma sintaxis en todos lados. Todavía puede hacer ptr_arg [0] como si se hubiera declarado como una matriz. –

+0

@Hans Solo quiero entender si es sintácticamente posible hacerlo con notación de matriz '[]'. Sin razón específica. Solo quiero aclarar si es posible o no (solo para saber en el futuro y no perder el tiempo pensando si es posible o no una y otra vez). – ovgolovin

+0

No creo que haya ninguna necesidad de declarar el puntero como const, ya que se pasará por valor de todos modos. Solo si explícitamente desea proteger de la asignación (la copia del puntero en la pila) dentro de la definición de funciones. –

Respuesta

16

En C hay que poner const entre el [], por extraño que pudiera parecer a una persona sin preparación

void foo(char arr_arg[const]); 

Esto es "nuevo" C99-specific syntax. En C89/90 o C++ no hay forma de hacerlo con la sintaxis de "matriz", por lo que debe cambiar a la sintaxis "puntero" equivalente, como se sugiere en la respuesta de David.

+0

¡Gracias! Aceptaré la respuesta en unos minutos (cuando SO me permita hacerlo). ¿Podría escribir algunas palabras sobre lo que son C99, C89/90 (para aquellos que leerán esta respuesta, para que parte de ellos no busquen en Google para aclarar cuáles son)? – ovgolovin

+0

@ovgolovin agregado en C99 en 6.7.5.3p7 – ouah

+1

@ovgolovin: Tenga en cuenta que el argumento todavía no es una matriz, sino un * puntero *, y ese puntero se copia, lo que significa que el puntero original (y matriz) no se puede cambiar dentro de la función. Si está hablando de matrices reales (en lugar de memoria asignada dinámicamente), la matriz es inmutable (los contenidos pueden cambiarse, pero la matriz como contenedor no puede) por lo que tiene poco sentido marcarlo como 'const' –

8

El primero es que en su firma particular, el argumento es transformada por el compilador en un puntero, así que lo que tienes es:

void foo(char * arg); 

Ahora, hay dos entidades que se pueden hacer const en esa firma: el puntero y el tipo puntiagudo. Para hacer el tipo de punta se puede hacer const de dos maneras aún equivalentes diferentes [*]:

void foo(const char * arg); 
void foo(char const * arg); 

El puntero se podría hacer const con la sintaxis:

void foo(char * const arg); 

Pero tenga en cuenta que en una firma de función , de la misma manera que char arg[] se transforma en un puntero char *arg, se descarta el calificador de nivel superior. Por lo que desde el punto de vista de la declaración, estos dos son equivalentes:

void foo(char * const arg); 
void foo(char *  arg); 

En la definición, la const nivel superior se puede utilizar para indicar al compilador que el puntero del argumento (por valor) no debe ser cambiado dentro de la función, y detectará si intenta restablecer el puntero a una ubicación diferente. Pero, si solo el puntero es const, entonces el compilador con mucho gusto le permitirá modificar la memoria apuntada. Si no desea que la función cambie el contenido de la matriz, debe optar por una de las primeras dos firmas.

[*] que tienden a preferir el formato char const *, ya que proporciona una forma consistente de tipos de lectura: de derecha a izquierda se lee: un puntero no constante a un const char. Además, es más sencillo razonar sobre los tipos typedef-ed (al realizar una sustitución directa en la expresión). Dados typedef char* char_p;, const char_p y char_p const son ambos equivalentes a char * const y diferentes de const char *. Al usar consistentemente const a la derecha, puede simplemente sustituir ciegamente el typedef y leer el tipo sin tener que razonar.

2

Sí, en C esto es posible ya C99:

void foo(char ptr_arg[const]); 

es una sintaxis válida y equivalente a

void foo(char *const ptr_arg); 

más general, la [] puede contener cualquier calificador tipo, static y una expresión entera. Pero

Los calificadores de tipo opcional y la palabra clave static deberá aparecer sólo en una declaración de un parámetro de función con un tipo de matriz, y luego sólo en la derivación tipo de matriz externa.

que es para la dimensión que es equivalente a la declaración del puntero.

+0

@MooingDuck , Nunca dije que sea para C++, por ahora lo enfatizo en C. Y el OP aún afirma que él también está interesado en C, por lo que esta respuesta no hace daño. –

+0

Perdón por equivocarse. Solo pensé que es lo mismo en C y C++. Pero luego, cuando me preguntaron, solo dejé C++ (qué compilador estoy usando ahora). Pero de hecho, es muy interesante saber acerca de C también. Ahora sé que era imposible y solo fue posible con la llegada de C99. – ovgolovin

0

Para C++, la respuesta de Mooing Duck con la plantilla es la más directa.

Si tiene código C que está llamando a una interfaz de C implementado en C++, le pegan con convertir el argumento en un argumento de un puntero en su lugar, y haciendo que const

Si se va a utilizar Boost's array en lugar de utilizar C arrays directamente, entonces sería capaz de hacer que const, aunque también sería una función de plantilla:

template <unsigned N> 
void foo (Boost::array<char, N> const & arg) {} 

la ventaja de Boost::array es que le da la capacidad de hacer una asignación de peso ligero de una matriz fuera la pila, pero ser capaz de completar y usa algoritmos STL que dependen de los rasgos en el contenedor.

+0

Cuidado con ese segundo, ya que es diferente de lo que se pidió y todas las otras respuestas en la página. Los datos a los que apunta la matriz son locales, y _also_const. –

+0

@MooingDuck: modifiqué la respuesta para señalar la ventaja de usar Boost :: array sobre una matriz de estilo C en C++ y +1 en su publicación. – jxh

2

Hay varias formas en C++, pero ninguna es bastante lo que parece estar esperando.

//typedef has a very clear intent 
typedef char* array; 
void f0(const array a) {} 

//switch to pointers to sidestep the problem 
void f1(char* const a) {} 

//references are inherently const 
//can't take pointers, but guarantees the size, sometimes nice 
//this version obviously doesn't work in C 
template<int n> 
void f2(char (&a)[n]) {} 

http://ideone.com/4LvYT

+0

¿No es 'void f0 (const array a)' lo mismo que 'void f0 (const char * a)' (que hace que 'char' sea constante, no' a')? – ovgolovin

+0

no, 'array' es un tipo completo, y' const array' hace una variable 'const' de tipo' array'. Es un truco muy común al pasar por los punteros de función, ya que de lo contrario la sintaxis es difícil de manejar. –

Cuestiones relacionadas