'const int' กับ 'int const' เป็นพารามิเตอร์ฟังก์ชันใน C ++ และ C


116

พิจารณา:

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

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

สองหน้าที่นี้เหมือนกันทุกประการหรือไม่หรือมีความแตกต่างกันอย่างไร?

ฉันสนใจคำตอบสำหรับภาษา C แต่ถ้ามีอะไรน่าสนใจในภาษา C ++ ฉันก็อยากรู้เช่นกัน


ตอนนี้มีคีย์เวิร์ด const ใน C หรือไม่? ไม่เคยมีมาก่อน แต่ฉันไม่ค่อยคุ้นเคยกับมาตรฐาน C 99
Onorio Catenacci

8
คุณไม่จำเป็นต้องเป็น C90 ก็เพียงพอแล้ว มันไม่ได้อยู่ใน K&R C ดั้งเดิม
Mark Baker

3
เป็นคีย์เวิร์ดใน C89 และ ANSI ฉันไม่รู้ว่ามันเป็นคีย์เวิร์ดในสมัย ​​Kerningham และ Richie หรือเปล่า
Nils Pipenbrinck

7
เว็บไซต์นี้แปลว่า "C พูดพล่อยๆ" เป็นภาษาอังกฤษcdecl.org
Motti

5
ผมว่า "C พูดพล่อยๆไปพูดพล่อยๆภาษาอังกฤษ" แต่ก็ยังดี :)
คอส

คำตอบ:


176

const TและT constเหมือนกัน ด้วยประเภทตัวชี้จะซับซ้อนมากขึ้น:

  1. const char* เป็นตัวชี้ค่าคงที่ char
  2. char const* เป็นตัวชี้ค่าคงที่ char
  3. char* const เป็นตัวชี้ค่าคงที่ไปยัง a (เปลี่ยนแปลงได้) char

กล่าวอีกนัยหนึ่ง (1) และ (2) เหมือนกัน วิธีเดียวในการสร้างตัวชี้ (แทนที่จะเป็นพอยน์เตอร์) constคือการใช้คำต่อท้ายconst-

นี่คือเหตุผลที่หลายคนชอบวางประเภทconstให้ถูกต้องเสมอ(รูปแบบ“ East const”): ทำให้ตำแหน่งของมันสัมพันธ์กับประเภทที่สอดคล้องกันและง่ายต่อการจดจำ (นอกจากนี้ยังดูเหมือนว่าจะทำให้ง่ายต่อการสอนสำหรับผู้เริ่มต้น )


2
C มี const ให้: คง const char foo [] = "foo"; คุณไม่ควรเปลี่ยนแปลง foo
James Antill

4
K&R C ไม่มี const; C90 (และ C99) ทำ มีข้อ จำกัด เล็กน้อยเมื่อเทียบกับ C ++ แต่ก็มีประโยชน์
Mark Baker

นี่เป็นความจริงสำหรับการอ้างอิงหรือไม่?
Ken

1
@ เคนใช่เหมือนกัน
Konrad Rudolph

1
@ étale-cohomology จุดดีเสริม. ควรจะมีมาตลอด
Konrad Rudolph

339

เคล็ดลับคือการอ่านคำประกาศย้อนหลัง (ขวาไปซ้าย):

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

ทั้งสองอย่างคือสิ่งเดียวกัน ดังนั้น:

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

เคล็ดลับการอ่านย้อนหลังมีประโยชน์อย่างยิ่งเมื่อคุณต้องจัดการกับการประกาศที่ซับซ้อนมากขึ้นเช่น:

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
แล้ว "ถ่าน const * u" ล่ะ? สิ่งนี้อ่าน "ตัวชี้ไปยังอักขระคงที่" หรือ "ตัวชี้ที่มีค่าคงที่สำหรับอักขระ" หรือไม่ ดูเหมือนจะคลุมเครือ มาตรฐานกล่าวว่าอดีต แต่ในการค้นหาสิ่งนี้คุณต้องคำนึงถึงลำดับความสำคัญและกฎการเชื่อมโยง
Panayiotis Karabassis

5
@PanayiotisKarabassis ทุกคนควรได้รับการปฏิบัติเหมือนโซ่คำคุณศัพท์โดยไม่ต้องแลกเปลี่ยนสถานที่ใด ๆ char const *อ่านจากซ้ายไปขวาคือ: "pointer, const, char" เป็นตัวชี้ไปยัง const char เมื่อคุณพูดว่า "ตัวชี้ที่คงที่" คำคุณศัพท์ "ค่าคงที่" จะอยู่บนตัวชี้ ดังนั้นในกรณีนี้รายการคำคุณศัพท์ของคุณควรเป็น: "const, pointer, char" จริงๆ แต่คุณพูดถูกมีความคลุมเครือสำหรับเคล็ดลับนี้ มันเป็น "เคล็ดลับ" จริงๆมากกว่า "กฎ" ที่ชัดเจน
Ates Goral

5
เมื่อคุณประกาศชุดค่าผสมระหว่างอาร์เรย์ฟังก์ชันตัวชี้และตัวชี้ฟังก์ชันการอ่านย้อนหลังจะไม่ทำงานอีกต่อไป (น่าเศร้า) อย่างไรก็ตามคุณสามารถอ่านประกาศยุ่งเหล่านี้ในรูปแบบเกลียว คนอื่น ๆ รู้สึกผิดหวังกับการคิดค้น Go
Martin JH

@Martin JH: พวกเขาไม่สามารถทำลายด้วยการพิมพ์ดีดได้หรือ? และ / หรือใช้การอ้างอิงเพื่อกำจัด indirections?
Peter Mortensen

14

ไม่มีความแตกต่างกัน ทั้งสองประกาศว่า "a" เป็นจำนวนเต็มที่ไม่สามารถเปลี่ยนแปลงได้

สถานที่ที่ความแตกต่างเริ่มปรากฏคือเมื่อคุณใช้พอยน์เตอร์

ทั้งสองอย่างนี้:

const int *a
int const *a

ประกาศ "a" เพื่อเป็นตัวชี้ไปยังจำนวนเต็มที่ไม่เปลี่ยนแปลง "a" สามารถกำหนดให้ แต่ "* a" ไม่ได้

int * const a

ประกาศว่า "a" เป็นตัวชี้ค่าคงที่เป็นจำนวนเต็ม สามารถกำหนด "* a" ให้ แต่ "a" ไม่ได้

const int * const a

ประกาศว่า "a" เป็นตัวชี้ค่าคงที่เป็นจำนวนเต็มคงที่ ไม่สามารถกำหนด "a" หรือ "* 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;
}

ตัวอย่างสุดท้ายคือคำอธิบายที่ง่ายที่สุดเยี่ยมมาก!
ออก

7

Prakash ถูกต้องว่าคำประกาศเหมือนกันแม้ว่าคำอธิบายเพิ่มเติมเล็กน้อยเกี่ยวกับตัวชี้กรณีอาจเป็นไปตามลำดับ

"const int * p" เป็นตัวชี้ไปยัง int ที่ไม่อนุญาตให้เปลี่ยน int ผ่านตัวชี้นั้น "int * const p" เป็นตัวชี้ไปยัง int ที่ไม่สามารถเปลี่ยนให้ชี้ไปที่ int อื่นได้

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


จุดยึด ("faq-18.5.) เสียควรอ้างถึงอันไหน (มีหลายตัวที่มี" const "และ" * ")
Peter Mortensen

@PeterMortensen: ใช่ลิงค์เน่า ขอบคุณ ฉันอัปเดตลิงค์
Fred Larson

5

const intจะเหมือนกับint constเช่นเดียวกับที่เป็นจริงกับประเภทสเกลาร์ทั้งหมดใน C โดยทั่วไปการประกาศพารามิเตอร์ฟังก์ชันสเกลาร์ตามที่constไม่ต้องการเนื่องจากความหมายของการเรียกตามค่าของ C หมายความว่าการเปลี่ยนแปลงใด ๆ ในตัวแปรจะเป็นแบบโลคัลสำหรับฟังก์ชันการปิดล้อม


4

นี่ไม่ใช่คำตอบโดยตรง แต่เป็นเคล็ดลับที่เกี่ยวข้อง เพื่อให้สิ่งต่างๆตรงฉันมักจะใช้การพาความร้อน "วางconstด้านนอก" โดยที่ "นอก" ฉันหมายถึงด้านซ้ายสุดหรือขวาสุด วิธีนี้จะไม่มีความสับสน - const ใช้กับสิ่งที่ใกล้เคียงที่สุด (ไม่ว่าจะเป็นประเภทหรือ*) เช่น,



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 ทำให้ const อะไรก็ตามที่เหลืออยู่" เช่น "int * const foo" ทำให้ตัวชี้เป็น "const" เนื่องจากตัวชี้ถูกปล่อยไว้ อย่างไรก็ตามคุณจะต้องเขียนบรรทัดที่สอง "int const * bar" ทำให้ int const เนื่องจากเหลือไว้ "int const * const * qux" ทำให้ทั้งสองเป็น int และตัวชี้ const เนื่องจากค่าใดค่าหนึ่งถูกทิ้งไว้
Mecki

4

เหมือนกัน แต่ใน C ++ มีเหตุผลที่ดีที่จะใช้ const ทางด้านขวาเสมอ คุณจะสอดคล้องกันทุกที่เพราะต้องประกาศฟังก์ชันสมาชิก const ด้วยวิธีนี้:

int getInt() const;

มันเปลี่ยนแปลงthisตัวชี้ในการทำงานจากการFoo * const ดูที่นี่.Foo const * const


3
นี่คือ const ที่แตกต่างกันอย่างสิ้นเชิง
Justin Meiners

1
ทำไมถึงแตกต่างกันอย่างสิ้นเชิง? แตกต่างกันมากพอที่จะได้รับการโหวตลดลง
Nick Westgate

1
ใช่คำถามเกี่ยวกับความแตกต่างระหว่าง "const int" และ "int const" คำตอบของคุณไม่เกี่ยวข้องกับคำถามนี้
Justin Meiners

1
ฉันบอกว่าพวกเขาเหมือนกัน แต่คำตอบที่ได้รับการยอมรับและได้รับการโหวตสูงสุดยังให้ข้อมูลเพิ่มเติมเกี่ยวกับประเภทตัวชี้ คุณลดคะแนนเหล่านั้นด้วยหรือไม่?
Nick Westgate

3

ใช่พวกเขาเหมือนกันเพียง int

และแตกต่างกันสำหรับ int*


5
(const int *) และ (int const *) เหมือนกันแตกต่างจาก (int * const)
James Antill

3

ฉันคิดว่าในกรณีนี้มันเหมือนกัน แต่นี่คือตัวอย่างที่คำสั่งมีความสำคัญ:

const int* cantChangeTheData;
int* const cantChangeTheAddress;

2
อันที่จริง แต่ int const * เหมือนกับครั้งแรกดังนั้นลำดับของ int และ const จึงไม่สำคัญมันเป็นเพียงลำดับของ * และ const ที่เป็นเช่นนั้น
Mark Baker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.