C ++ ve C'deki işlev parametreleri olarak 'const int' ve 'int const' karşılaştırması


116

Düşünmek:

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

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

Bu iki işlev her açıdan aynı mı yoksa bir fark var mı?

C dili için bir cevapla ilgileniyorum, ancak C ++ dilinde ilginç bir şey varsa, ben de bilmek isterim.


Şimdi C'de bir const anahtar sözcüğü var mı? Eskiden yoktu ama C 99 standardına pek aşina değilim.
Onorio Catenacci

8
Olmana gerek yok. C90 yeterlidir. Orijinal K&R C'de değildi.
Mark Baker

3
C89 ve ANSI'de bir anahtar sözcüktür. Kerningham ve Richie günlerinde bir anahtar kelime miydi bilmiyorum.
Nils Pipenbrinck

7
Bu site İngilizce "C anlamsız" çevirir cdecl.org
Motti

5
"İngilizce anlamsız cümbüşe anlamsız" derdim, ama yine de güzel :)
Kos

Yanıtlar:


175

const Tve T constaynıdır. İşaretçi türleriyle daha karmaşık hale gelir:

  1. const char* sabiti gösteren bir göstericidir char
  2. char const* sabiti gösteren bir göstericidir char
  3. char* const sabit bir göstericidir (değiştirilebilir) char

Diğer bir deyişle, (1) ve (2) aynıdır. İşaretçi yapmanın tek yolu (pointee yerine) constbir sonek kullanmaktır.const .

Bu nedenle birçok kişi yazının her zaman constsağ tarafına koymayı tercih eder ("Doğu konst" stili): türüne göre konumunu tutarlı ve hatırlanması kolay hale getirir (ayrıca anekdot olarak yeni başlayanlara öğretmeyi kolaylaştırıyor gibi görünüyor ).


2
C'nin sabiti vardır: static const char foo [] = "foo"; foo'yu değiştirmesen iyi olur.
James Antill

4
K&R C'nin sabiti yoktu; C90 (ve C99) yapar. C ++ ile karşılaştırıldığında biraz sınırlı, ancak kullanışlıdır.
Mark Baker

bu aynı zamanda referanslar için de geçerli mi?
Ken

1
@Ken Evet, aynı.
Konrad Rudolph

1
@ étale-cohomology İyi nokta eklendi. Başından beri orada olmalıydı.
Konrad Rudolph

339

İşin püf noktası, beyanı geriye doğru okumaktır (sağdan sola):

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

İkisi de aynı şey. Bu nedenle:

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

Geriye doğru okuma hilesi özellikle aşağıdakiler gibi daha karmaşık bildirimlerle uğraşırken işe yarar:

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
peki ya "char const * u"? Burada "Sabit bir karaktere işaretçi" veya "bir karaktere sabit olan bir işaretçi" mi okunuyor? Belirsiz görünüyor. Standart ilkini söylüyor, ancak bunu bulmak için öncelik ve çağrışım kurallarını hesaba katmalısınız.
Panayiotis Karabassis

5
@PanayiotisKarabassis Tümü, herhangi bir yer değiştirmeden bir sıfat zinciri olarak ele alınmalıdır. char const *, soldan sağa okunur: "işaretçi, sabit, karakter". Bu sabit karaktere bir gösterici. "Sabit olan bir işaretçi" dediğinizde, "sabit" sıfatı işaretçi üzerindedir. Yani, bu durumda, sıfat listeniz gerçekten şöyle olmalıdır: "const, pointer, char". Ama haklısın, bu numarada belirsizlik var. Bu gerçekten bir "numara", kesin bir "kural" dan daha fazlası.
Ates Goral

5
Dizi, işlev, işaretçi ve işlev göstericisinin vahşi bir kombinasyonunu bildirdiğinizde, geriye doğru okuma artık çalışmıyor (ne yazık ki). Ancak, bu dağınık beyanları spiral bir düzende okuyabilirsiniz . Diğerleri onlar tarafından o kadar hayal kırıklığına uğradılar ki Go'yu icat ettiler.
Martin JH

@Martin JH: Daktilo ile parçalanamazlar mı? Ve / veya indirimleri ortadan kaldırmak için referanslar kullanıyor musunuz?
Peter Mortensen

14

Fark yok. Her ikisi de "a" nın değiştirilemeyen bir tamsayı olduğunu beyan eder.

Farklılıkların ortaya çıkmaya başladığı yer, işaretçiler kullandığınız zamandır.

Bunların ikisi de:

const int *a
int const *a

"a" nın değişmeyen bir tamsayıya işaretçi olduğunu beyan edin. "a" atanabilir ancak "* a" atanamaz.

int * const a

"a" nın bir tamsayıya sabit bir gösterici olduğunu bildirir. "* a" atanabilir ancak "a" atanamaz.

const int * const a

"a" nın sabit bir tam sayıya sabit bir gösterici olduğunu bildirir. Ne "a" ne de "* a" atanamaz.

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;
}

Son örnek en basit açıklamadır, harika!
exru

7

Prakash, beyanların aynı olduğu konusunda haklıdır, ancak işaretçi durumunun biraz daha fazla açıklaması sırayla olabilir.

"const int * p", int'in bu işaretçiyle değiştirilmesine izin vermeyen bir int göstericisidir. "int * const p", başka bir int'i gösterecek şekilde değiştirilemeyen bir int göstericisidir.

Bkz. Https://isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-const .


Çapa ("sss-18.5.) Bozuk. Hangisine atıfta bulunulmalı (" const "ve" * "ile birkaç tane var)?
Peter Mortensen

@PeterMortensen: Evet, bağlantı çürümesi. Teşekkürler. Bağlantıyı güncelledim.
Fred Larson

5

const intint constC'deki tüm skaler türlerde olduğu gibi, ile aynıdır . Genel olarak, bir skaler fonksiyon parametresinin constgerekli olmadığı gibi bildirilmesi , çünkü C'nin değer bazında çağrı semantiği, değişkendeki herhangi bir değişikliğin onu kapsayan fonksiyon için yerel olduğu anlamına gelir.


4

Bu doğrudan bir cevap değil, ilgili bir ipucu. Her şeyi düz tutmak için, her zaman " constdışarıya koy" konveksiyonunu kullanırım, "dışarıdan" kastettiğim en sol veya en sağdır. Bu şekilde karışıklık olmaz - sabit en yakın şey için geçerlidir (tür veya tür *). Örneğin,



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
"Const, geride kalan her şeyi const yapar" kuralını kullanmanız daha iyi olabilir. Örneğin, "int * const foo", işaretçiyi "const" yapar, çünkü işaretçi onun solundadır. Bununla birlikte, ikinci satıra "int const * bar" yazarsınız, int const yapar, çünkü ona bırakılmıştır. "int const * const * qux", hem int hem de işaretçiyi sabit yapar, çünkü ikisinden biri de ona bırakılır.
Mecki

4

Bunlar aynıdır, ancak C ++ 'da her zaman sağda const kullanmak için iyi bir neden vardır. Const üye işlevler her yerde çünkü tutarlı olacak olmalıdır şöyle bildirilebilir:

int getInt() const;

Bu değişiklikler thisile ilgili fonksiyon işaretçi Foo * constiçin Foo const * const. Buraya bakın.


3
Bu tamamen farklı bir tür sabittir.
Justin Meiners

1
Bu neden tamamen farklı? Olumsuz oy almak için yeterince farklı.
Nick Westgate

1
Evet, soru "const int" ve "int const" arasındaki farkla ilgili, cevabınızın bununla hiçbir ilgisi yok.
Justin Meiners

1
Aynı olduklarını söyledim. Yine de kabul edilen ve en çok oylanan cevaplar, işaretçi türleri hakkında ek bilgi verir. Bunları da red mi ettiniz?
Nick Westgate

3

Evet, sadece aynı int

ve farklı int*


5
(const int *) ve (int const *) aynıdır, sadece (int * const) 'dan farklıdır.
James Antill

3

Sanırım bu durumda ikisi aynı, ama işte düzenin önemli olduğu bir örnek:

const int* cantChangeTheData;
int* const cantChangeTheAddress;

2
Aslında, ancak int const * birinciyle aynıdır, dolayısıyla int ve const'ın sırası önemli değildir, yalnızca * ve const'ın sırasıdır.
Mark Baker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.