ทำไมตัวแปรชื่อโปรแกรมเมอร์ซีส่วนใหญ่เช่นนี้:
int *myVariable;
มากกว่าเช่นนี้
int* myVariable;
ทั้งสองถูกต้อง ดูเหมือนว่าฉันว่าเครื่องหมายดอกจันเป็นส่วนหนึ่งของประเภทไม่ใช่ส่วนหนึ่งของชื่อตัวแปร ใครสามารถอธิบายเหตุผลนี้
ทำไมตัวแปรชื่อโปรแกรมเมอร์ซีส่วนใหญ่เช่นนี้:
int *myVariable;
มากกว่าเช่นนี้
int* myVariable;
ทั้งสองถูกต้อง ดูเหมือนว่าฉันว่าเครื่องหมายดอกจันเป็นส่วนหนึ่งของประเภทไม่ใช่ส่วนหนึ่งของชื่อตัวแปร ใครสามารถอธิบายเหตุผลนี้
คำตอบ:
พวกมันเทียบเท่ากันหมด อย่างไรก็ตามใน
int *myVariable, myVariable2;
ดูเหมือนว่าเห็นได้ชัดว่า myVariable มีประเภทint *ในขณะที่ myVariable2 มีประเภทint ใน
int* myVariable, myVariable2;
มันอาจจะดูเหมือนเห็นได้ชัดว่าทั้งสองเป็นประเภทint *แต่ที่ไม่ถูกต้องตามที่myVariable2
มีประเภทint
ดังนั้นสไตล์การเขียนโปรแกรมแรกจึงใช้งานง่ายกว่า
int* someVar
โครงการส่วนบุคคล มันสมเหตุสมผลมากขึ้น
int[10] x
. นี่ไม่ใช่ไวยากรณ์ของ C ไวยากรณ์แยกวิเคราะห์อย่างชัดเจนว่า: int (*x)
และไม่เป็น(int *) x
ดังนั้นการวางเครื่องหมายดอกจันทางซ้ายเป็นเพียงการทำให้เข้าใจผิดและยึดตามความเข้าใจผิดของไวยากรณ์การประกาศ C
int* myVariable; int myVariable2;
แทน
หากคุณดูอีกวิธีหนึ่ง*myVariable
เป็นประเภทint
ที่เหมาะสม
myVariable
สามารถเป็น NULL ซึ่งในกรณีนี้*myVariable
ทำให้เกิดความผิดพลาดในการแบ่งกลุ่ม แต่ไม่มีประเภท NULL
int x = 5; int *pointer = &x;
เพราะมันชี้ให้เห็นว่าเรากำหนดค่าเป็น*pointer
บางค่าไม่ใช่pointer
ตัวของมันเอง
เนื่องจาก * ในบรรทัดนั้นผูกกับตัวแปรมากกว่าประเภท:
int* varA, varB; // This is misleading
@Lundin ชี้ให้เห็นด้านล่าง const เพิ่มรายละเอียดปลีกย่อยที่น่าสนใจมากขึ้น คุณสามารถเลี่ยงขั้นตอนนี้ได้โดยการประกาศหนึ่งตัวแปรต่อบรรทัดซึ่งไม่ชัดเจน:
int* varA;
int varB;
ความสมดุลระหว่างโค้ดที่ชัดเจนและโค้ดที่กระชับนั้นยากที่จะตี - บรรทัดที่ซ้ำซ้อนจำนวนโหลที่int a;
ไม่ดีเช่นกัน ยังฉันเริ่มต้นที่หนึ่งประกาศต่อบรรทัดและกังวลเกี่ยวกับการรวมรหัสในภายหลัง
int *const a, b;
พิจารณา * "ผูก" อยู่ที่ไหน ประเภทของa
คือint* const
ดังนั้นคุณจะพูดได้อย่างไรว่า * เป็นของตัวแปรเมื่อมันเป็นส่วนหนึ่งของประเภทตัวเอง?
บางสิ่งบางอย่างที่ไม่มีใครพูดถึงที่นี่จนถึงขณะนี้คือเครื่องหมายดอกจันเป็น " ผู้ควบคุมการปฏิเสธ " ในซี
*a = 10;
บรรทัดข้างต้นไม่ได้หมายความว่าผมต้องการที่จะกำหนด10
ไปa
ก็หมายความว่าผมต้องการที่จะกำหนด10
สิ่งที่หน่วยความจำตำแหน่งa
จุดที่จะต้อง และฉันไม่เคยเห็นใครเขียน
* a = 10;
มีไหม ดังนั้นโอเปอเรเตอร์ที่ถูกปฏิเสธจะถูกเขียนโดยไม่มีที่ว่าง นี่อาจเป็นความแตกต่างจากการคูณที่ข้ามหลายบรรทัด:
x = a * b * c * d
* e * f * g;
นี่*e
จะทำให้เข้าใจผิดใช่มั้ย
โอเคตอนนี้บรรทัดต่อไปนี้หมายถึงอะไรจริง:
int *a;
คนส่วนใหญ่จะพูดว่า:
หมายความว่าa
เป็นตัวชี้ไปยังint
ค่า
นี่เป็นเทคนิคที่ถูกต้องคนส่วนใหญ่ชอบที่จะเห็น / อ่านอย่างนั้นและนั่นคือวิธีที่มาตรฐาน C สมัยใหม่จะกำหนดไว้ (โปรดทราบว่าภาษา C เองมีมาก่อนมาตรฐาน ANSI และ ISO ทั้งหมด) แต่มันไม่ใช่วิธีเดียวที่จะมองมัน คุณยังสามารถอ่านบรรทัดนี้ได้ดังนี้:
มูลค่าของ dereferenced เป็นประเภทa
int
ดังนั้นในความเป็นจริงเครื่องหมายดอกจันในการประกาศนี้ยังสามารถถูกมองว่าเป็นตัวดำเนินการอ้างอิงซึ่งอธิบายถึงตำแหน่งของมันด้วย และนั่นก็a
คือพอยน์เตอร์ไม่ได้ประกาศเลยจริงๆมันคือความจริงที่ว่าสิ่งเดียวที่คุณสามารถอ้างถึงได้คือพอยเตอร์
มาตรฐาน C กำหนดเพียงสองความหมายต่อ*
ผู้ปฏิบัติงาน:
และการอ้อมเป็นเพียงความหมายเดียวไม่มีความหมายพิเศษสำหรับการประกาศตัวชี้มีเพียงการอ้อมซึ่งเป็นสิ่งที่การดำเนินการตามกฎหมายทำมันทำการเข้าถึงทางอ้อมดังนั้นภายในคำสั่งเช่นint *a;
นี้เป็นการเข้าถึงทางอ้อม( *
หมายถึง การเข้าถึงทางอ้อม) และทำให้ข้อความที่สองข้างต้นมีความใกล้เคียงกับมาตรฐานมากกว่าข้อความแรกคือ
int a, *b, (*c)();
สิ่งที่ชอบ "ประกาศวัตถุต่อไปนี้เป็นint
: วัตถุa
วัตถุที่ชี้ไปตามb
และวัตถุกลับมาจากฟังก์ชั่นชี้ไปตามc
"
*
ในint *a;
ไม่ได้เป็นผู้ดำเนินการและจะไม่ dereferencing a
(ซึ่งไม่ได้ถูกกำหนดแม้ยัง)
*
(มันให้เพียงความหมายเพื่อการแสดงออกทั้งหมดไม่ให้*
ภายในแสดงออก!) มันบอกว่า "int a;" ประกาศตัวชี้ซึ่งทำไม่เคยอ้างสิทธิ์เป็นอย่างอื่น แต่ไม่มีความหมายที่กำหนดให้*
อ่านเป็น * ค่าที่ไม่ลงรอยกันของa
intนั้นยังคงใช้ได้โดยสมบูรณ์เนื่องจากมีความหมายตามจริงเหมือนกัน ไม่มีอะไรจริง ๆ ไม่มีอะไรเขียนใน 6.7.6.1 จะขัดแย้งกับคำสั่งนั้น
int *a;
เป็นการประกาศไม่ใช่นิพจน์ a
ไม่ได้ dereferenced int *a;
โดย a
ยังไม่ปรากฏว่า*
มีการดำเนินการ คุณคิดว่าint *a = NULL;
เป็นข้อผิดพลาดหรือไม่เพราะมันเป็นตัวชี้ null?
ฉันจะไปบนกิ่งก้านที่นี่และบอกว่ามีคำตอบที่ตรงกับคำถามนี้int *myVariable;
ทั้งสำหรับการประกาศตัวแปรและพารามิเตอร์และผลตอบแทนประเภทซึ่งเป็นที่เครื่องหมายดอกจันควรไปถัดจากชื่อ: หากต้องการชื่นชมว่าทำไมให้ดูวิธีที่คุณประกาศสัญลักษณ์ประเภทอื่นใน C:
int my_function(int arg);
สำหรับฟังก์ชั่น;
float my_array[3]
สำหรับอาร์เรย์
รูปแบบทั่วไปเรียกว่าการประกาศตามการใช้งานคือชนิดของสัญลักษณ์จะแบ่งออกเป็นส่วนหนึ่งก่อนชื่อและส่วนรอบชื่อและส่วนเหล่านี้รอบชื่อเลียนแบบไวยากรณ์ที่คุณจะใช้เพื่อให้ได้ ค่าของประเภททางด้านซ้าย:
int a_return_value = my_function(729);
float an_element = my_array[2];
และ: int copy_of_value = *myVariable;
.
C ++ ขว้างประแจในการทำงานกับการอ้างอิงเนื่องจากไวยากรณ์ที่จุดที่คุณใช้การอ้างอิงเหมือนกับของประเภทค่าดังนั้นคุณสามารถยืนยันว่า C ++ ใช้วิธีการที่แตกต่างกับ C ในทางกลับกัน C ++ ยังคงเหมือนเดิม พฤติกรรมของ C ในกรณีของพอยน์เตอร์ดังนั้นการอ้างอิงจึงเป็นสิ่งที่แปลกในแง่นี้
นั่นเป็นเพียงเรื่องของการตั้งค่า
เมื่อคุณอ่านโค้ดการแยกความแตกต่างระหว่างตัวแปรและพอยน์เตอร์นั้นง่ายกว่าในกรณีที่สอง แต่มันอาจทำให้เกิดความสับสนเมื่อคุณวางทั้งตัวแปรและพอยน์เตอร์ของประเภททั่วไปไว้ในบรรทัดเดียว เพราะลดความสามารถในการอ่าน)
ฉันชอบที่จะประกาศพอยน์เตอร์ด้วยเครื่องหมายที่เกี่ยวข้องของพวกเขาถัดจากพิมพ์ชื่อเช่น
int* pMyPointer;
กูรูที่ยิ่งใหญ่เคยกล่าวว่า "อ่านวิธีการแปลคุณต้อง"
http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835
ได้รับสิ่งนี้อยู่ในหัวข้อของตำแหน่ง const แต่กฎเดียวกันใช้ที่นี่
คอมไพเลอร์อ่านว่า:
int (*a);
ไม่เป็น:
(int*) a;
ถ้าคุณติดดาวที่ติดกับตัวแปรมันจะทำให้การประกาศของคุณง่ายต่อการอ่าน นอกจากนี้ยังหลีกเลี่ยงการปวดตาเช่น:
int* a[10];
- แก้ไข -
เพื่ออธิบายว่าสิ่งที่ฉันหมายถึงเมื่อบอกว่ามันแยกวิเคราะห์เป็นint (*a)
ที่หมายความว่า*
ผูกให้กระชับยิ่งขึ้นไปa
กว่าจะint
ในมากลักษณะที่ว่าในการแสดงออก4 + 3 * 7
3
ผูกให้กระชับยิ่งขึ้นไป7
มากกว่าที่จะเกิดจากความสำคัญที่สูงขึ้นของ4
*
ด้วยการขอโทษสำหรับศิลปะ ASCII สรุปของ AST สำหรับการแยกวิเคราะห์int *a
มีลักษณะเช่นนี้:
Declaration
/ \
/ \
Declaration- Init-
Secifiers Declarator-
| List
| |
| ...
"int" |
Declarator
/ \
/ ...
Pointer \
| Identifier
| |
"*" |
"a"
เป็นที่แสดงให้เห็นอย่างชัดเจน*
ผูกให้กระชับยิ่งขึ้นไปa
ตั้งแต่บรรพบุรุษร่วมกันของพวกเขาคือDeclarator
ในขณะที่คุณจะต้องไปตลอดทางขึ้นต้นไม้เพื่อที่จะหาบรรพบุรุษร่วมกันที่เกี่ยวข้องกับการDeclaration
int
(int*) a
ไม่มีคอมไพเลอร์แน่นอนที่สุดอ่านประเภทเป็น
int
ในกรณีนี้. ขั้นตอนที่ 2 อ่านประกาศรวมถึงการตกแต่งประเภทใด ๆ *a
ในกรณีนี้. ขั้นตอนที่ 3 อ่านตัวละครถัดไป ถ้าเครื่องหมายจุลภาคกินมันและกลับไปที่ขั้นตอนที่ 2 ถ้าเครื่องหมายอัฒภาคหยุด หากสิ่งอื่นโยนข้อผิดพลาดทางไวยากรณ์ ...
int* a, b;
และรับพอยน์เตอร์ได้ จุดที่ฉันทำคือการ*
ผูกกับตัวแปรและแยกวิเคราะห์กับมันไม่ได้มีประเภทในการสร้าง "ประเภทฐาน" ของการประกาศ นั่นเป็นส่วนหนึ่งของเหตุผลที่มีการพิมพ์ typedefs เพื่ออนุญาตให้typedef int *iptr;
iptr a, b;
สร้างตัวชี้สองสามตัว โดยใช้ typedef ที่คุณสามารถผูกกับ*
int
Declaration-Specifier
กับ "การตกแต่ง" ในการที่Declarator
จะมาถึงประเภทสุดท้ายสำหรับแต่ละตัวแปร แต่มันไม่ได้ "ย้าย" ตกแต่งเพื่อระบุการประกาศเป็นอย่างอื่นint a[10], b;
จะให้ผลลัพธ์ที่ไร้สาระอย่างสมบูรณ์มันจะแยกวิเคราะห์เป็นint *a, b[10];
int
*a
,
b[10]
;
ไม่มีวิธีอื่นที่จะอธิบายว่าเหมาะสม
int*a
การอ่านนั้นอยู่ในท้ายที่สุดโดยคอมไพเลอร์ว่า: " a
has type int*
" นั่นคือสิ่งที่ฉันหมายถึงด้วยความคิดเห็นเดิมของฉัน
เนื่องจากเหมาะสมกว่าเมื่อคุณมีคำประกาศเช่น:
int *a, *b;
int* a, b;
ทำให้ตัวชี้ไปยังb
int
แต่พวกเขาไม่ได้ และด้วยเหตุผลที่ดี ภายใต้ระบบที่เสนอของคุณประเภทของb
การประกาศต่อไปนี้int* a[10], b;
คืออะไร?
สำหรับการประกาศพอยน์เตอร์หลาย ๆ ตัวในหนึ่งบรรทัดฉันชอบint* a, * b;
ที่จะประกาศว่า "a" เป็นตัวชี้ไปยังจำนวนเต็มโดยสังหรณ์ใจมากขึ้นและไม่ผสมผสานรูปแบบเมื่อประกาศ "b" เช่นเดียวกัน เหมือนมีคนพูดว่าฉันจะไม่ประกาศสองประเภทที่แตกต่างกันในแถลงการณ์เดียวกัน
ผู้ที่ต้องการint* x;
พยายามบังคับให้รหัสของพวกเขาเข้าสู่โลกแห่งนิยายโดยที่ประเภทนั้นอยู่ทางซ้ายและตัวระบุ (ชื่อ) อยู่ทางขวา
ฉันพูดว่า "ตัวละคร" เพราะ:
ใน C และ C ++ ในกรณีทั่วไปตัวระบุที่ประกาศจะถูกล้อมรอบด้วยข้อมูลประเภท
นั่นอาจฟังดูบ้า แต่คุณรู้ว่ามันเป็นจริง นี่คือตัวอย่างบางส่วน:
int main(int argc, char *argv[])
หมายถึง " main
เป็นฟังก์ชั่นที่ใช้int
และอาร์เรย์ของพอยน์เตอร์ไปchar
และส่งคืนint
" กล่าวอีกนัยหนึ่งคือข้อมูลประเภทส่วนใหญ่อยู่ทางด้านขวา บางคนคิดว่าการประกาศฟังก์ชั่นไม่นับเพราะพวกเขา "พิเศษ" อย่างใด ตกลงมาลองตัวแปรกัน
void (*fn)(int)
หมายความว่าfn
เป็นตัวชี้ไปยังฟังก์ชั่นที่ใช้int
และส่งคืนอะไร
int a[10]
ประกาศ 'a' เป็นอาร์เรย์ 10 int
s
pixel bitmap[height][width]
.
เห็นได้ชัดว่าฉันเลือกตัวอย่างเชอร์รี่ที่มีข้อมูลจำนวนมากทางด้านขวาเพื่อให้ประเด็นของฉัน มีจำนวนมากของการประกาศเป็นที่มากที่สุด - ถ้าไม่ทั้งหมด - struct { int x; int y; } center
ประเภทที่อยู่ทางด้านซ้ายเช่น
ไวยากรณ์การประกาศนี้ขยายตัวออกมาจากความปรารถนาของ K & R ที่จะให้การประกาศสะท้อนถึงการใช้งาน การอ่านการประกาศอย่างง่ายนั้นง่ายและการอ่านสิ่งที่ซับซ้อนมากขึ้นสามารถเรียนรู้ได้โดยการเรียนรู้กฎทางซ้าย - ขวา - ขวา (บางครั้งเรียกกฎเกลียวหรือเพียงแค่กฎซ้าย - ขวา)
C ก็เพียงพอที่เรียบง่ายที่โปรแกรมเมอร์ C int *p
หลายโอบกอดรูปแบบนี้และเขียนประกาศง่ายๆเป็น
ใน C ++ ไวยากรณ์มีความซับซ้อนเพิ่มขึ้นเล็กน้อย (ด้วยคลาสการอ้างอิงเท็มเพลตคลาส enum) และเพื่อตอบสนองต่อความซับซ้อนนั้นคุณจะเห็นความพยายามมากขึ้นในการแยกประเภทจากตัวระบุในการประกาศหลาย ๆ กล่าวอีกนัยหนึ่งคุณอาจเห็นการint* p
ประกาศสไตล์มากกว่าถ้าคุณลองดูรหัส C ++ ขนาดใหญ่
ในภาษาใดภาษาหนึ่งคุณสามารถมีประเภทที่ด้านซ้ายของการประกาศตัวแปรโดย (1) ไม่เคยประกาศตัวแปรหลายตัวในคำสั่งเดียวกันและ (2) การใช้typedef
s (หรือนามแฝงการประกาศซึ่งน่าขันทำให้ชื่อแทน ตัวระบุทางด้านซ้ายของประเภท) ตัวอย่างเช่น:
typedef int array_of_10_ints[10];
array_of_10_ints a;
(*fn)
ตำแหน่งของพอยน์เตอร์ที่สัมพันธ์กับfn
ไม่ใช่ประเภทที่ส่งคืน
ฉันตอบคำถามคล้าย ๆ กันใน CP แล้วและเนื่องจากไม่มีใครพูดถึงที่นี่ฉันต้องชี้ให้เห็นว่าC เป็นภาษารูปแบบฟรีไม่ว่าคุณจะเลือกสไตล์แบบใดก็ตามในขณะที่ parser สามารถแยกโทเค็นแต่ละแบบได้ ความไม่ชอบมาพากลนี้ C นำไปสู่การเป็นชนิดพิเศษมากของการประกวดที่เรียกว่าC ประกวด
ข้อโต้แย้งจำนวนมากในหัวข้อนี้เป็นเรื่องส่วนตัวและข้อโต้แย้งเกี่ยวกับ "ดาวผูกกับชื่อตัวแปร" นั้นไร้เดียงสา นี่คือข้อโต้แย้งเล็กน้อยที่ไม่ได้เป็นเพียงความคิดเห็น:
ตัวระบุประเภทตัวชี้ที่ถูกลืม
อย่างเป็นทางการ "ดาว" ไม่เป็นชนิดไม่ให้ชื่อตัวแปรมันเป็นส่วนหนึ่งของตัวเองรายการไวยากรณ์ชื่อของตัวชี้ ไวยากรณ์ C ทางการ (ISO 9899: 2018) คือ:
(6.7) การประกาศ:
declaration-specifiers init-declarator-list เลือก;
โดยที่declaration-specifiersมีประเภท (และที่เก็บข้อมูล) และinit-declarator-listมีตัวชี้และชื่อตัวแปร ซึ่งเราจะเห็นว่าเราแยกไวยากรณ์ลิสต์ของตัวประกาศนี้หรือไม่:
(6.7.6) ผู้ประกาศ:
ตัวเลือก opt direct-declarator
... ตัวชี้
(6.7.6) :
*
ประเภทตัวระบุ qualifier รายการopt
*
-qualifier ประเภทรายการตัวเลือก opt
โดยที่ declarator คือการประกาศทั้งหมด direct-declarator คือตัวระบุ (ชื่อตัวแปร) และตัวชี้คือดาวตามด้วยรายการตัวระบุประเภทชนิดทางเลือกที่เป็นของตัวชี้
สิ่งที่ทำให้ข้อโต้แย้งรูปแบบต่างๆเกี่ยวกับ "ดาวเป็นของตัวแปร" ไม่สอดคล้องกันคือพวกเขาลืมเกี่ยวกับตัวระบุประเภทตัวชี้เหล่านี้ int* const x
, int *const x
หรือint*const x
?
พิจารณาint *const a, b;
, ประเภทของอะไรa
และb
? ไม่ชัดเจนว่า "ดาวเป็นของตัวแปร" อีกต่อไป ค่อนข้างจะเริ่มไตร่ตรองที่const
เป็นของ
คุณสามารถสร้างข้อโต้แย้งเสียงที่แน่นอนว่าดาวนั้นเป็นของตัวระบุประเภทตัวชี้
รายการตัวระบุชนิดของตัวชี้อาจทำให้เกิดปัญหาสำหรับผู้ที่ใช้int *a
สไตล์ ผู้ที่ใช้พอยน์เตอร์ภายในtypedef
(ซึ่งเราไม่ควรเป็นแบบฝึกหัดที่แย่มาก!) และคิดว่า "ดาวนี้เป็นชื่อของตัวแปร" มักจะเขียนบั๊กที่บอบบางมากนี้:
/*** bad code, don't do this ***/
typedef int *bad_idea_t;
...
void func (const bad_idea_t *foo);
คอมไพล์นี้หมดจด ตอนนี้คุณอาจคิดว่ารหัสถูกต้องแล้ว ไม่เช่นนั้น! รหัสนี้เป็นความถูกต้องโดยไม่ตั้งใจของปลอม
ชนิดของfoo
เป็นจริงint*const*
- ตัวชี้ภายนอกส่วนใหญ่สร้างขึ้นแบบอ่านอย่างเดียวไม่ใช่ชี้ไปที่ข้อมูล ดังนั้นในฟังก์ชั่นนี้เราสามารถทำได้**foo = n;
และมันจะเปลี่ยนค่าตัวแปรในตัวเรียก
นี่เป็นเพราะในการแสดงออกconst bad_idea_t *foo
ที่*
ไม่ได้อยู่ในชื่อตัวแปรที่นี่! ในรหัสหลอกประกาศพารามิเตอร์นี้คือการอ่านเป็นconst (bad_idea_t *) foo
และไม่ได้(const bad_idea_t) *foo
เป็น ดาวเป็นของประเภทตัวชี้ที่ซ่อนอยู่ในกรณีนี้ - ชนิดเป็นตัวชี้และตัวชี้ const *const
ที่มีคุณสมบัติเขียนเป็น
แต่แล้วรากเหง้าของปัญหาในตัวอย่างข้างต้นคือการฝึกฝนการซ่อนพอยน์เตอร์ไว้ด้านหลังtypedef
และไม่ใช่*
สไตล์
เกี่ยวกับการประกาศตัวแปรหลายตัวในบรรทัดเดียว
ประกาศตัวแปรหลายบนบรรทัดเดียวได้รับการยอมรับอย่างกว้างขวางว่าเป็นปฏิบัติไม่ดี1) CERT-C สรุปผลรวมเป็นอย่างดีเช่น:
DCL04-C อย่าประกาศมากกว่าหนึ่งตัวแปรต่อการประกาศ
เพียงแค่อ่านภาษาอังกฤษจากนั้นสามัญสำนึกยอมรับว่า การประกาศควรเป็นการประกาศอย่างใดอย่างหนึ่ง
และมันก็ไม่สำคัญว่าตัวแปรจะเป็นตัวชี้หรือไม่ การประกาศตัวแปรแต่ละตัวในบรรทัดเดียวทำให้โค้ดนั้นชัดเจนในเกือบทุกกรณี
ข้อโต้แย้งเกี่ยวกับโปรแกรมเมอร์ที่สับสนint* a, b
คือไม่ดี รากของปัญหาคือการใช้ declarators *
หลายที่ไม่ได้ตำแหน่งของ คุณควรเขียนสิ่งนี้แทน:
int* a; // or int *a
int b;
อีกเสียงหนึ่ง แต่เป็นการโต้แย้งแบบอัตนัย int* a
ประเภทของa
นั้นไม่มีคำถามint*
และดังนั้นดาวจึงอยู่ในประเภท qualifier
แต่โดยพื้นฐานแล้วข้อสรุปของฉันคือข้อโต้แย้งมากมายที่โพสต์ที่นี่เป็นเพียงเรื่องส่วนตัวและไร้เดียงสา คุณไม่สามารถสร้างข้อโต้แย้งที่ถูกต้องสำหรับทั้งสองสไตล์ - มันเป็นเรื่องของความชอบส่วนตัวแบบส่วนตัว
1) CERT-C DCL04-C
typedef int *bad_idea_t;
void func(const bad_idea_t bar);
ตามที่นักพยากรณ์ผู้ยิ่งใหญ่ Dan Saks สอน "ถ้าคุณวางสิ่งconst
ที่ถูกต้องให้มากที่สุดเท่าที่จะทำได้โดยไม่ต้องเปลี่ยนความหมายเชิงความหมาย" จะเป็นปัญหา นอกจากนี้ยังทำให้const
การประกาศของคุณสอดคล้องกับการอ่านมากขึ้น "ทุกอย่างทางด้านขวาของคำว่า const คือตัวที่ทุกตัวทางซ้ายคือประเภทของมัน" สิ่งนี้จะใช้กับ const ทั้งหมดในการประกาศ ลองใช้กับint const * * const x;
พิจารณา
int *x = new int();
สิ่งนี้ไม่แปล
int *x;
*x = new int();
จริง ๆ แล้วแปลเป็น
int *x;
x = new int();
ทำให้int *x
สัญกรณ์ค่อนข้างไม่สอดคล้องกัน
new
เป็นตัวดำเนินการ C ++ คำถามของเขาถูกแท็ก "C" และไม่ใช่ "C ++"
typedefs
แต่นั่นจะเพิ่มความซับซ้อนที่ไม่จำเป็น IMHO