'const int' vs. 'int const' como parámetros de función en C ++ y C


116

Considerar:

int testfunc1 (const int a)
{
  return a;
}

int testfunc2 (int const a)
{
  return a;
}

¿Son estas dos funciones iguales en todos los aspectos o hay alguna diferencia?

Estoy interesado en una respuesta para el lenguaje C, pero si hay algo interesante en el lenguaje C ++, me gustaría saberlo también.


¿Hay una palabra clave constante en C ahora? No solía haberlo, pero no estoy tan familiarizado con el estándar C 99.
Onorio Catenacci

8
No necesitas estarlo. C90 es suficiente. Sin embargo, no estaba en el K&R C original.
Mark Baker

3
Es una palabra clave en C89 y ANSI. No sé si era una palabra clave en los días de Kerningham y Richie.
Nils Pipenbrinck

7
Este sitio traduce "galimatías C" al inglés cdecl.org
Motti

5
Yo diría "galimatías de C a galimatías en inglés", pero sigue siendo agradable :)
Kos

Respuestas:


175

const Ty T constson idénticos. Con los tipos de puntero se vuelve más complicado:

  1. const char* es un puntero a una constante char
  2. char const* es un puntero a una constante char
  3. char* const es un puntero constante a a (mutable) char

En otras palabras, (1) y (2) son idénticos. La única forma de hacer el puntero (en lugar del puntero) constes usar un sufijo- const.

Esta es la razón por la que muchas personas prefieren colocar siempre consten el lado derecho del tipo (estilo "East const"): hace que su ubicación en relación con el tipo sea consistente y fácil de recordar (también anecdóticamente parece facilitar la enseñanza a los principiantes ).


2
C tiene constante, dado: static const char foo [] = "foo"; es mejor que no alteres foo.
James Antill

4
K&R C no tenía const; C90 (y C99) lo hace. Es un poco limitado en comparación con C ++, pero es útil.
Mark Baker

¿Esto también es cierto para las referencias?
Ken

1
@Ken Sí, es lo mismo.
Konrad Rudolph

1
@ étale-cohomology Buen punto, agregó. Debería haber estado allí todo el tiempo.
Konrad Rudolph

339

El truco consiste en leer la declaración al revés (de derecha a izquierda):

const int a = 1; // read as "a is an integer which is constant"
int const a = 1; // read as "a is a constant integer"

Ambos son lo mismo. Por lo tanto:

a = 2; // Can't do because a is constant

El truco de leer al revés es especialmente útil cuando se trata de declaraciones más complejas como:

const char *s;      // read as "s is a pointer to a char that is constant"
char c;
char *const t = &c; // read as "t is a constant pointer to a char"

*s = 'A'; // Can't do because the char is constant
s++;      // Can do because the pointer isn't constant
*t = 'A'; // Can do because the char isn't constant
t++;      // Can't do because the pointer is constant

5
¿qué pasa con "char const * u"? ¿Se lee "Un puntero a un carácter constante" o "un puntero que es constante a un carácter"? Parece ambiguo. El estándar dice lo primero, pero para averiguarlo hay que tener en cuenta las reglas de precedencia y asociatividad.
Panayiotis Karabassis

5
@PanayiotisKarabassis Todo debe tratarse como una cadena de adjetivos, sin intercambiar ningún lugar. char const *, leído de izquierda a derecha es: "puntero, const, char". Es un puntero para const char. Cuando dice "un puntero que es constante", el adjetivo "constante" está en el puntero. Entonces, para ese caso, su lista de adjetivos debería haber sido realmente: "const, pointer, char". Pero tienes razón, hay ambigüedad en este truco. Es realmente un "truco", más que una "regla" definitiva.
Ates Goral

5
Cuando declara una combinación salvaje de matriz, función, puntero y puntero de función, la lectura hacia atrás ya no funciona (lamentablemente). Sin embargo, puede leer estas declaraciones desordenadas en un patrón en espiral . Otros estaban tan frustrados por ellos que inventaron Go.
Martin JH

@Martin JH: ¿No podrían dividirse mediante typedefs? ¿Y / o usar referencias para eliminar indirecciones?
Peter Mortensen

14

No hay diferencia. Ambos declaran que "a" es un número entero que no se puede cambiar.

El lugar donde comienzan a aparecer las diferencias es cuando usas punteros.

Ambos:

const int *a
int const *a

declare "a" como un puntero a un número entero que no cambia. Se puede asignar "a", pero no "* a".

int * const a

declara que "a" es un puntero constante a un número entero. Se puede asignar "* a", pero no "a".

const int * const a

declara que "a" es un puntero constante a un entero constante. No se puede asignar "a" ni "* a".

static int one = 1;

int testfunc3 (const int *a)
{
  *a = 1; /* Error */
  a = &one;
  return *a;
}

int testfunc4 (int * const a)
{
  *a = 1;
  a = &one; /* Error */
  return *a;
}

int testfunc5 (const int * const a)
{
  *a = 1;   /* Error */
  a = &one; /* Error */
  return *a;
}

El último ejemplo es la explicación más simple, ¡genial!
exru

7

Prakash tiene razón en que las declaraciones son las mismas, aunque podría ser necesario un poco más de explicación del caso del puntero.

"const int * p" es un puntero a un int que no permite cambiar el int a través de ese puntero. "int * const p" es un puntero a un int que no se puede cambiar para que apunte a otro int.

Consulte https://isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-const .


El ancla ("faq-18.5.) Está rota. ¿A cuál debería referirse (hay varias con" const "y" * ")?
Peter Mortensen

@PeterMortensen: Sí, link rot. Gracias. Actualicé el enlace.
Fred Larson

5

const intes idéntico a int const, como es cierto con todos los tipos escalares en C. En general, declarar un parámetro de función escalar como constno es necesario, ya que la semántica de llamada por valor de C significa que cualquier cambio en la variable es local a su función envolvente.


4

Esta no es una respuesta directa, sino un consejo relacionado. Para mantener las cosas en orden, siempre uso la convección "poner consten el exterior", donde por "exterior" me refiero al extremo izquierdo o al extremo derecho. De esa manera no hay confusión: la constante se aplica a lo más parecido (ya sea el tipo o el *). P.ej,



int * const foo = ...; // Pointer cannot change, pointed to value can change
const int * bar = ...; // Pointer can change, pointed to value cannot change
int * baz = ...; // Pointer can change, pointed to value can change
const int * const qux = ...; // Pointer cannot change, pointed to value cannot change

6
Quizás sea mejor usar la regla "const hace constante lo que quede de ella". Por ejemplo, "int * const foo" hace que el puntero sea "const", porque el puntero se deja en él. Sin embargo, escribiría la segunda línea "int const * bar", hace int const, porque se deja a ella. "int const * const * qux", hace que ambos, el int y el puntero, sean const, porque cualquiera de ellos se deja una vez.
Mecki

4

Son iguales, pero en C ++ hay una buena razón para usar siempre const a la derecha. Serás consistente en todas partes porque las funciones miembro const deben declararse de esta manera:

int getInt() const;

Cambia el thispuntero en la función de Foo * consta Foo const * const. Mira aquí.


3
Este es un tipo de constante completamente diferente.
Justin Meiners

1
¿Por qué esto es completamente diferente? Lo suficientemente diferente como para ganar un voto negativo.
Nick Westgate

1
Sí, la pregunta es sobre la diferencia entre "const int" e "int const", su respuesta no tiene nada que ver con eso.
Justin Meiners

1
Dije que son iguales. Y, sin embargo, las respuestas aceptadas y mejor votadas también brindan información adicional sobre los tipos de punteros. ¿También los rechazaste?
Nick Westgate

3

Si, son iguales por solo int

y diferente para int*


5
(const int *) e (int const *) son iguales, solo que son diferentes de (int * const).
James Antill

3

Creo que en este caso son iguales, pero aquí hay un ejemplo donde el orden importa:

const int* cantChangeTheData;
int* const cantChangeTheAddress;

2
De hecho, pero int const * es lo mismo que el primero, por lo que el orden de int y const no importa, es solo el orden de * y la const lo que importa.
Mark Baker
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.