'const int' vs. 'int const' sebagai parameter fungsi di C ++ dan C

116

Mempertimbangkan:

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

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

Apakah kedua fungsi ini sama di setiap aspek atau ada perbedaan?

Saya tertarik dengan jawaban untuk bahasa C, tetapi jika ada sesuatu yang menarik dalam bahasa C ++, saya ingin mengetahuinya juga.

Nils Pipenbrinck
sumber
Apakah sekarang ada kata kunci const di C? Dulu tidak ada tapi saya tidak begitu akrab dengan standar C 99.
Onorio Catenacci
8
Anda tidak perlu seperti itu. C90 sudah cukup. Itu tidak ada di K&R C asli.
Mark Baker
3
Ini adalah kata kunci di C89 dan ANSI. Saya tidak tahu apakah itu kata kunci di masa Kerningham dan Richie.
Nils Pipenbrinck
7
Situs ini menerjemahkan "C omong kosong" ke bahasa Inggris cdecl.org
Motti
5
Saya akan mengatakan "C omong kosong ke bahasa Inggris omong kosong", tapi masih bagus :)
Kos

Jawaban:

175

const Tdan T constidentik. Dengan tipe pointer, ini menjadi lebih rumit:

  1. const char* adalah penunjuk ke sebuah konstanta char
  2. char const* adalah penunjuk ke sebuah konstanta char
  3. char* const adalah penunjuk konstan ke (bisa berubah) char

Dengan kata lain, (1) dan (2) identik. Satu-satunya cara untuk membuat pointer (daripada pointee) constadalah dengan menggunakan sufiks- const.

Inilah sebabnya mengapa banyak orang lebih suka untuk selalu menempatkan constdi sisi kanan jenis (gaya "East const"): ini membuat lokasinya relatif terhadap jenis yang konsisten dan mudah diingat (juga secara anekdot tampaknya membuatnya lebih mudah untuk diajarkan kepada pemula ).

Konrad Rudolph
sumber
2
C memang memiliki const, diberikan: static const char foo [] = "foo"; Anda lebih baik tidak mengubah foo.
James Antill
4
K&R C tidak memiliki const; C90 (dan C99) tidak. Ini agak terbatas dibandingkan dengan C ++, tetapi ini berguna.
Mark Baker
apakah ini juga berlaku untuk referensi?
Ken
1
@Ken Ya, sama saja.
Konrad Rudolph
1
@ étale-cohomology Poin yang bagus, ditambahkan. Seharusnya sudah ada selama ini.
Konrad Rudolph
339

Triknya adalah membaca deklarasi secara terbalik (kanan-ke-kiri):

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

Keduanya adalah hal yang sama. Karena itu:

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

Trik membaca mundur sangat berguna ketika Anda berurusan dengan deklarasi yang lebih kompleks seperti:

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
sumber
5
bagaimana dengan "char const * u"? Apakah ini membaca "Penunjuk ke karakter konstan" atau "penunjuk yang konstan ke karakter"? Sepertinya ambigu. Standar mengatakan yang pertama, tetapi untuk mengetahuinya, Anda harus mempertimbangkan aturan presedensi dan asosiatif.
Panayiotis Karabassis
5
@PanayiotisKarabassis Semua harus diperlakukan sebagai rangkaian kata sifat, tanpa bertukar tempat. char const *, dibaca dari kiri ke kanan adalah: "pointer, const, char". Ini adalah penunjuk ke const char. Saat Anda mengatakan "penunjuk yang konstan", kata sifat "konstan" ada di penunjuk. Jadi, untuk kasus ini, daftar kata sifat Anda seharusnya benar-benar: "const, pointer, char". Tapi Anda benar, ada ambiguitas dalam trik ini. Ini benar-benar sebuah "tipuan", lebih dari sekedar "aturan" yang pasti.
Ates Goral
5
Saat Anda mendeklarasikan kombinasi liar dari larik, fungsi, penunjuk, dan penunjuk fungsi, pembacaan mundur tidak berfungsi lagi (sayangnya). Namun, Anda dapat membaca deklarasi yang berantakan ini dalam pola spiral . Yang lain begitu frustrasi dengan mereka sehingga mereka menemukan Go.
Martin JH
@ Martin JH: Tidak bisakah mereka dipecah melalui typedefs? Dan / atau menggunakan referensi untuk menghilangkan tipuan?
Peter Mortensen
14

Tidak ada perbedaan. Keduanya menyatakan "a" sebagai bilangan bulat yang tidak dapat diubah.

Tempat di mana perbedaan mulai muncul adalah saat Anda menggunakan petunjuk.

Keduanya:

const int *a
int const *a

mendeklarasikan "a" sebagai penunjuk ke integer yang tidak berubah. "a" bisa ditetapkan ke, tapi "* a" tidak bisa.

int * const a

menyatakan "a" sebagai penunjuk konstan ke integer. "* a" bisa ditetapkan ke, tapi "a" tidak bisa.

const int * const a

menyatakan "a" sebagai penunjuk konstan ke bilangan bulat konstan. Baik "a" maupun "* a" tidak dapat ditetapkan ke.

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
sumber
Contoh terakhir adalah penjelasan paling sederhana, bagus!
exru
7

Prakash benar bahwa deklarasinya sama, meskipun sedikit lebih banyak penjelasan tentang kasus penunjuk mungkin sesuai.

"const int * p" adalah penunjuk ke int yang tidak mengizinkan int untuk diubah melalui penunjuk itu. "int * const p" adalah penunjuk ke int yang tidak bisa diubah untuk menunjuk ke int lain.

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

Fred Larson
sumber
Jangkar ("faq-18.5.) Rusak. Yang mana yang harus dirujuk (ada beberapa dengan" const "dan" * ")?
Peter Mortensen
@PeterMortensen: Ya, link rot. Terima kasih. Saya memperbarui tautan.
Fred Larson
5

const intidentik dengan int const, seperti halnya dengan semua jenis skalar di C. Secara umum, mendeklarasikan parameter fungsi skalar sebagai consttidak diperlukan, karena semantik panggilan-demi-nilai C berarti bahwa setiap perubahan pada variabel bersifat lokal ke fungsi penutupnya.

Emerick Rogul
sumber
4

Ini bukan jawaban langsung tetapi tip terkait. Untuk menjaga hal-hal tetap lurus, saya selalu menggunakan konveksi "letakkan constdi luar", sedangkan "di luar" yang saya maksud adalah paling kiri atau paling kanan. Dengan cara itu tidak ada kebingungan - const berlaku untuk hal terdekat (baik tipe atau *). Misalnya,



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
sumber
6
Anda mungkin lebih baik menggunakan aturan "const membuat const apa pun yang tersisa". Misalnya "int * const foo" menjadikan pointer "const", karena pointer diserahkan ke sana. Namun, Anda akan menulis baris kedua "int const * bar", membuat int const, karena dibiarkan begitu saja. "int const * const * qux", membuat keduanya, int dan pointer const, karena salah satunya diserahkan ke sana.
Mecki
4

Keduanya sama, tetapi di C ++ ada alasan bagus untuk selalu menggunakan const di sebelah kanan. Anda akan konsisten di mana-mana karena fungsi anggota const harus dideklarasikan dengan cara ini:

int getInt() const;

Ini mengubah thispenunjuk dalam fungsi dari Foo * constmenjadi Foo const * const. Lihat disini.

Nick Westgate
sumber
3
Ini adalah jenis const yang sama sekali berbeda.
Justin Meiners
1
Mengapa ini sangat berbeda? Cukup berbeda untuk mendapatkan suara negatif.
Nick Westgate
1
Ya, pertanyaannya adalah tentang perbedaan antara "const int" dan "int const", jawaban Anda tidak ada hubungannya dengan itu.
Justin Meiners
1
Saya mengatakan mereka sama. Namun jawaban yang diterima dan paling banyak dipilih juga memberikan info tambahan tentang jenis penunjuk. Apakah Anda juga tidak menyukai itu?
Nick Westgate
3

Ya, mereka sama saja int

dan berbeda untuk int*

prakash
sumber
5
(const int *) dan (int const *) sama, hanya berbeda dari (int * const).
James Antill
3

Saya pikir dalam hal ini mereka sama, tetapi berikut adalah contoh di mana urutan itu penting:

const int* cantChangeTheData;
int* const cantChangeTheAddress;
pengguna7545
sumber
2
Memang, tapi int const * sama dengan yang pertama, jadi urutan int dan const tidak menjadi masalah, hanya urutan * dan konstanta yang penting.
Mark Baker