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.