'const int' vs. 'int const' als Funktionsparameter in C ++ und C.

115

Erwägen:

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

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

Sind diese beiden Funktionen in jeder Hinsicht gleich oder gibt es einen Unterschied?

Ich bin an einer Antwort für die C-Sprache interessiert, aber wenn die C ++ - Sprache etwas Interessantes enthält, würde ich es auch gerne wissen.

Nils Pipenbrinck
quelle
Gibt es jetzt ein const-Schlüsselwort in C? Früher gab es keine, aber ich bin mit dem C 99-Standard nicht so vertraut.
Onorio Catenacci
8
Das musst du nicht sein. C90 ist genug. Es war jedoch nicht im Original K & R C.
Mark Baker
3
Es ist ein Schlüsselwort in C89 und ANSI. Ich weiß nicht, ob es in den Tagen von Kerningham und Richie ein Schlüsselwort war.
Nils Pipenbrinck
7
Diese Seite übersetzt "C Kauderwelsch" ins Englische cdecl.org
Motti
5
Ich würde sagen "C Kauderwelsch zu Englisch Kauderwelsch", aber immer noch nett :)
Kos

Antworten:

175

const Tund T constsind identisch. Mit Zeigertypen wird es komplizierter:

  1. const char* ist ein Zeiger auf eine Konstante char
  2. char const* ist ein Zeiger auf eine Konstante char
  3. char* const ist ein konstanter Zeiger auf a (veränderlich) char

Mit anderen Worten sind (1) und (2) identisch. Die einzige Möglichkeit, den Zeiger (und nicht den Zeiger) constzu erstellen, besteht darin, ein Suffix- zu verwenden const.

Aus diesem Grund ziehen es viele Menschen vor, immer constauf die rechte Seite des Typs zu setzen („East const“ -Stil): Dadurch wird seine Position relativ zum Typ konsistent und leicht zu merken (es scheint auch anekdotisch einfacher zu sein, Anfängern beizubringen ).

Konrad Rudolph
quelle
2
C hat const, gegeben: static const char foo [] = "foo"; du solltest besser nicht foo ändern.
James Antill
4
K & R C hatte keine Konstante; C90 (und C99) tun dies. Es ist im Vergleich zu C ++ etwas eingeschränkt, aber es ist nützlich.
Mark Baker
gilt das auch für referenzen?
Ken
1
@ Ken Ja, es ist das gleiche.
Konrad Rudolph
1
@ étale-kohomology Guter Punkt, hinzugefügt. Hätte die ganze Zeit dort sein sollen.
Konrad Rudolph
339

Der Trick besteht darin, die Deklaration rückwärts zu lesen (von rechts nach links):

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

Beides ist dasselbe. Deshalb:

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

Der Trick zum Rückwärtslesen ist besonders praktisch, wenn Sie mit komplexeren Deklarationen wie den folgenden umgehen:

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
Ates Goral
quelle
5
was ist mit "char const * u"? Liest dies "Ein Zeiger auf ein konstantes Zeichen" oder "Ein Zeiger, der auf ein Zeichen konstant ist"? Scheint mehrdeutig. Der Standard sagt das erstere, aber um dies herauszufinden, müssen Sie die Vorrang- und Assoziativitätsregeln berücksichtigen.
Panayiotis Karabassis
5
@PanayiotisKarabassis Alle sollten als eine Kette von Adjektiven behandelt werden, ohne Orte zu tauschen. char const *, von links nach rechts gelesen lautet: "pointer, const, char". Es ist ein Zeiger auf const char. Wenn Sie "ein Zeiger, der konstant ist" sagen, befindet sich das Adjektiv "konstant" auf dem Zeiger. In diesem Fall hätte Ihre Adjektivliste also wirklich lauten müssen: "const, pointer, char". Aber Sie haben Recht, dieser Trick ist nicht eindeutig. Es ist wirklich ein "Trick", mehr als eine definitive "Regel".
Ates Goral
5
Wenn Sie eine wilde Kombination aus Array, Funktion, Zeiger und Funktionszeiger deklarieren, funktioniert das Rückwärtslesen (leider) nicht mehr. Sie können diese unordentlichen Deklarationen jedoch spiralförmig lesen . Andere waren so frustriert von ihnen, dass sie Go erfanden.
Martin JH
@ Martin JH: Könnten sie nicht mit Hilfe von Typedefs aufgelöst werden? Und / oder Verweise verwenden, um Indirektionen zu beseitigen?
Peter Mortensen
14

Es gibt keinen Unterschied. Beide deklarieren "a" als eine Ganzzahl, die nicht geändert werden kann.

Die Stelle, an der Unterschiede auftreten, ist die Verwendung von Zeigern.

Beide:

const int *a
int const *a

Deklarieren Sie "a" als Zeiger auf eine Ganzzahl, die sich nicht ändert. "a" kann zugewiesen werden, "* a" jedoch nicht.

int * const a

deklariert "a" als konstanten Zeiger auf eine Ganzzahl. "* a" kann zugewiesen werden, "a" jedoch nicht.

const int * const a

deklariert "a" als konstanten Zeiger auf eine konstante Ganzzahl. Weder "a" noch "* a" können zugeordnet werden.

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;
}
Andru Luvisi
quelle
Das letzte Beispiel ist die einfachste Erklärung, großartig!
Exru
7

Prakash hat Recht, dass die Deklarationen gleich sind, obwohl eine etwas ausführlichere Erklärung des Zeigerfalls angebracht sein könnte.

"const int * p" ist ein Zeiger auf ein int, mit dem das int nicht über diesen Zeiger geändert werden kann. "int * const p" ist ein Zeiger auf ein int, das nicht geändert werden kann, um auf ein anderes int zu zeigen.

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

Fred Larson
quelle
Der Anker ("faq-18.5.) Ist gebrochen. Auf welchen sollte er sich beziehen (es gibt mehrere mit" const "und" * ")?
Peter Mortensen
@ PeterMortensen: Ja, Link Rot. Vielen Dank. Ich habe den Link aktualisiert.
Fred Larson
5

const intist identisch mit int const, wie es bei allen Skalartypen in C der Fall ist. Im Allgemeinen ist das Deklarieren eines Skalarfunktionsparameters als constnicht erforderlich, da die Call-by-Value-Semantik von C bedeutet, dass alle Änderungen an der Variablen lokal für die umschließende Funktion sind.

Emerick Rogul
quelle
4

Dies ist keine direkte Antwort, sondern ein verwandter Tipp. Um die Dinge gerade zu halten, verwende ich immer die Konvektion " constaußen angelegt", wobei mit "außen" ganz links oder ganz rechts gemeint ist. Auf diese Weise gibt es keine Verwirrung - die Konstante gilt für die nächste Sache (entweder den Typ oder die *). Z.B,



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
Pat Notz
quelle
6
Sie sind vielleicht besser dran, die Regel "const macht const, was auch immer davon übrig ist" zu verwenden. ZB macht "int * const foo" den Zeiger "const", weil der Zeiger ihm überlassen bleibt. Sie würden jedoch die zweite Zeile "int const * bar" schreiben, macht die int const, weil es ihr überlassen bleibt. "int const * const * qux" macht sowohl den int als auch den Zeiger const, weil einer von beiden einmal ihm überlassen ist.
Mecki
4

Sie sind die gleichen, aber in C ++ gibt es einen guten Grund, immer rechts const zu verwenden. Sie werden im Einklang überall da konstanten Elementfunktionen müssen auf diese Weise erklärt werden:

int getInt() const;

Es ändert den thisZeiger in der Funktion von Foo * constnach Foo const * const. Siehe hier.

Nick Westgate
quelle
3
Dies ist eine ganz andere Art von Konstante.
Justin Meiners
1
Warum ist das ganz anders? Anders genug, um eine Gegenstimme zu verdienen.
Nick Westgate
1
Ja, die Frage betrifft den Unterschied zwischen "const int" und "int const". Ihre Antwort hat nichts damit zu tun.
Justin Meiners
1
Ich sagte, sie sind gleich. Und doch geben die akzeptierten und am besten bewerteten Antworten auch zusätzliche Informationen zu Zeigertypen. Hast du diese auch abgelehnt?
Nick Westgate
3

Ja, sie sind nur für gleich int

und anders für int*

Prakash
quelle
5
(const int *) und (int const *) sind gleich, sie unterscheiden sich nur von (int * const).
James Antill
3

Ich denke in diesem Fall sind sie gleich, aber hier ist ein Beispiel, wo Ordnung wichtig ist:

const int* cantChangeTheData;
int* const cantChangeTheAddress;
user7545
quelle
2
In der Tat, aber int const * ist das gleiche wie das erste, also spielt die Reihenfolge von int und const keine Rolle, es ist nur die Reihenfolge von * und const, die dies tut.
Mark Baker