คำหลัก C auto ใช้ที่ไหน?


105

ในสมัยเรียนมหาวิทยาลัยฉันอ่านเกี่ยวกับautoคีย์เวิร์ดและในบางครั้งฉันก็ลืมไปว่ามันคืออะไร ถูกกำหนดให้เป็น:

กำหนดตัวแปรโลคัลว่ามีอายุการใช้งานโลคัล

ไม่เคยพบว่ามีการใช้งานที่ไหนมีการใช้งานจริงหรือไม่และถ้าเป็นเช่นนั้นจะใช้ที่ไหนและในกรณีใด

คำตอบ:


90

autoเป็นตัวปรับแต่งเช่นstatic. เป็นการกำหนดคลาสการจัดเก็บของตัวแปร อย่างไรก็ตามเนื่องจากค่าเริ่มต้นสำหรับตัวแปรในระบบคือautoโดยปกติคุณไม่จำเป็นต้องระบุด้วยตนเอง

หน้านี้แสดงรายการพื้นที่จัดเก็บข้อมูลต่างๆใน C


13
เพิ่งดูสิ่งนี้อีกครั้งหลังจากมีคนโหวตคำตอบของฉัน คุณบอกว่าคุณ "ไม่จำเป็นต้องระบุด้วยตนเอง" ฉันต้องถาม: มีสถานการณ์ที่auto สามารถระบุได้จริง แต่จะไม่เกิดขึ้นตามค่าเริ่มต้นหรือไม่?
Jerry Coffin

2
@JerryCoffin ไม่ได้อยู่ใน C ใน C ++ 11 มันถูกนำมาใช้ใหม่และคุณสามารถใช้เพื่อรับการอนุมานประเภทตัวแปรท้องถิ่นได้อย่างมีประสิทธิภาพ
Mehrdad Afshari

2
การใช้งานที่เป็นไปได้อย่างหนึ่งคือในการประกาศฟังก์ชันที่ซ้อนกันใน GNU C ไปข้างหน้าแม้ว่านี่จะเป็นการหักหลังคำจำกัดความดั้งเดิมของauto. tigcc.ticalc.org/doc/keywords.html#auto
Josiah

2
เพจที่ลิงก์ล้าสมัย ตั้งแต่ C11 ยังมี_Thread_localรายละเอียด: en.cppreference.com/w/c/language/storage_durationและstackoverflow.com/a/14289720/6557621
MCCCS

133

หากคุณอ่านรายการIAQ (คำถามที่ถามบ่อย) คุณจะทราบดีว่ารถยนต์มีประโยชน์ในการกำหนดหรือประกาศยานพาหนะเป็นหลัก:

auto my_car;

ยานพาหนะที่จอดกลางแจ้งเป็นประจำ:

extern auto my_car;

สำหรับผู้ที่ไม่มีอารมณ์ขันและต้องการ "คำตอบที่เป็นข้อเท็จจริง" คำตอบสั้น ๆ คือไม่เคยมีเหตุผลใด ๆ ที่จะใช้autoเลย เวลาเดียวที่คุณได้รับอนุญาตให้ใช้autoคือตัวแปรที่มีautoคลาสพื้นที่เก็บข้อมูลอยู่แล้วดังนั้นคุณเพียงแค่ระบุบางสิ่งที่จะเกิดขึ้นต่อไป การพยายามใช้autoกับตัวแปรใด ๆ ที่ไม่มีautoคลาสหน่วยเก็บข้อมูลอยู่แล้วจะส่งผลให้คอมไพเลอร์ปฏิเสธโค้ดของคุณ ฉันคิดว่าถ้าคุณต้องการได้รับทางเทคนิคการใช้งานของคุณไม่จำเป็นต้องเป็นคอมไพเลอร์ (แต่เป็น) และในทางทฤษฎีสามารถรวบรวมโค้ดต่อไปได้หลังจากออกการวินิจฉัย (แต่จะไม่ได้)

ภาคผนวกเล็ก ๆ โดยkaz :

นอกจากนี้ยังมี:

static auto my_car;

ซึ่งต้องได้รับการตรวจวินิจฉัยตามมาตรฐาน ISO C ซึ่งถูกต้องเนื่องจากมีการประกาศว่ารถเสีย การวินิจฉัยไม่มีค่าใช้จ่าย แต่การปิดไฟแดชบอร์ดจะทำให้คุณเสียค่าใช้จ่ายแปดสิบเหรียญ (ยี่สิบหรือน้อยกว่าหากคุณซื้อดองเกิล USB ของคุณเองสำหรับการวินิจฉัยออนบอร์ดจาก eBay)

ดังกล่าวข้างต้นextern auto my_carยังต้องการการวินิจฉัยและด้วยเหตุนี้จึงไม่มีการเรียกใช้ผ่านคอมไพเลอร์นอกจากโดยเจ้าหน้าที่ของเมืองที่ได้รับมอบหมายให้บังคับใช้ที่จอดรถ

หากคุณเห็นจำนวนมากextern static auto ...ในฐานรหัสใด ๆ แสดงว่าคุณอยู่ในย่านที่ไม่ดี มองหางานที่ดีกว่าทันทีก่อนที่ทั้งสถานที่จะเปลี่ยนเป็น Rust


@ ตัวเอง: ISO ดูเหมือนจะไม่รู้จัก "ISO 2011" คุณเชื่อว่ามันอาจทำให้เป็นมาตรฐานได้อย่างไร?
Jerry Coffin

6
เป็นเรื่องดีที่ฉันไม่มีกาแฟโคล่าสเตาท์หรือของเหลวสีเข้มอื่น ๆ ในปาก คุณจะเป็นหนี้ฉันหน้าจอคอมพิวเตอร์ @JerryCoffin เป็นอย่างนั้น คำตอบที่ดีที่สุดที่เคยมีมา!
David Hammen

2
@ แดน: คุณใช้เวลา "ค่อนข้างนาน" ในการอ่านข้อความ 5 บรรทัดและเข้าใจในส่วนที่ระบุว่า: "คำตอบสั้น ๆ คือไม่เคยมีเหตุผลใด ๆ ที่จะใช้ auto เลย"? อย่างจริงจัง? เมื่อพิจารณาถึงความคิดเห็นที่นำหน้าคุณทันทีดูเหมือนว่าอย่างน้อยก็มีคนไม่กี่คนที่คิดว่ามันมีส่วนช่วยในเชิงบวก
Jerry Coffin

@JerryCoffin ฉันอธิบายไปแล้วอ่านความคิดเห็นของฉันอีกครั้ง การมองย้อนกลับคือ 20/20
Dan Bechard

2
ฉันเพิ่งผ่านการปะทะที่รุนแรง (ปิดสองเลน) ซึ่งบ่งบอกถึงความจำเป็นสำหรับchar auto my_car;
สิ้นเชิง

47

autoคำหลักจะไม่ได้ผลในภาษา C เป็นเพราะก่อนหน้านี้ภาษา C มีภาษา B ซึ่งคำหลักนั้นจำเป็นสำหรับการประกาศตัวแปรท้องถิ่น (B ได้รับการพัฒนาเป็น NB ซึ่งกลายเป็น C)

นี่คือคู่มืออ้างอิงสำหรับ B

อย่างที่คุณเห็นคู่มือนี้เต็มไปด้วยตัวอย่างที่autoใช้ เป็นเช่นนี้เนื่องจากไม่มีintคีย์เวิร์ด คำหลักบางประเภทจำเป็นต้องพูดว่า "นี่คือการประกาศตัวแปร" และคำหลักนั้นยังระบุด้วยว่าเป็นคำหลักภายในหรือภายนอก ( autoเทียบกับextrn) หากคุณไม่ได้ใช้อย่างใดอย่างหนึ่งแสดงว่าคุณมีข้อผิดพลาดทางไวยากรณ์ กล่าวx, y;คือไม่ใช่การประกาศด้วยตัวเอง แต่auto x, y;เป็นการประกาศ

เนื่องจากรหัสฐานที่เขียนด้วย B จะต้องย้ายไปที่ NB และ C เมื่อภาษาได้รับการพัฒนาภาษาเวอร์ชันใหม่กว่าจึงมีสัมภาระบางส่วนเพื่อให้เข้ากันได้ย้อนหลังได้ดีขึ้นซึ่งแปลว่าใช้งานได้น้อยลง ในกรณีของautoโปรแกรมเมอร์ไม่จำเป็นต้องค้นหาทุกเหตุการณ์ที่เกิดขึ้นautoและลบออก

เห็นได้ชัดจากคู่มือว่าตอนนี้ "implicit int" ที่ล้าสมัยใน C (ความสามารถในการเขียนmain() { ... }โดยไม่ต้องมีintด้านหน้า) มาจาก B. นั่นคือคุณสมบัติความเข้ากันได้แบบย้อนกลับอีกอย่างหนึ่งเพื่อรองรับรหัส B ฟังก์ชันไม่มีประเภทการส่งคืนที่ระบุใน B เนื่องจากไม่มีประเภท ทุกอย่างเป็นคำเช่นเดียวกับในภาษาแอสเซมบลีหลายภาษา

สังเกตว่าฟังก์ชันสามารถประกาศได้อย่างไรextrn putcharจากนั้นสิ่งเดียวที่ทำให้เป็นฟังก์ชันที่ตัวระบุใช้ : มันถูกใช้ในนิพจน์การเรียกฟังก์ชันเช่นputchar(x)และนั่นคือสิ่งที่บอกให้คอมไพเลอร์ถือว่าคำที่ไม่มีประเภทนั้นเป็นตัวชี้ฟังก์ชัน


26

ใน C autoคือคีย์เวิร์ดที่บ่งชี้ว่าตัวแปรเป็นแบบโลคัลสำหรับบล็อก เนื่องจากเป็นค่าเริ่มต้นสำหรับตัวแปร block-scoped จึงไม่จำเป็นและใช้น้อยมาก (ฉันไม่คิดว่าฉันเคยเห็นมันใช้นอกตัวอย่างในข้อความที่พูดถึงคำหลัก) ฉันจะสนใจว่ามีใครสามารถชี้ให้เห็นถึงกรณีที่autoจำเป็นต้องใช้เพื่อให้ได้การแยกวิเคราะห์หรือพฤติกรรมที่ถูกต้อง

อย่างไรก็ตามในมาตรฐาน C ++ 11 autoคำหลักถูก 'จี้' เพื่อสนับสนุนการอนุมานประเภทโดยที่ประเภทของตัวแปรสามารถนำมาจากประเภทของตัวเริ่มต้น:

auto someVariable = 1.5;   // someVariable will have type double

การอนุมานประเภทส่วนใหญ่จะถูกเพิ่มเพื่อสนับสนุนการประกาศตัวแปรในเทมเพลตหรือส่งคืนจากฟังก์ชันเทมเพลตโดยที่ประเภทตามพารามิเตอร์เทมเพลต (หรือสรุปโดยคอมไพเลอร์เมื่อเทมเพลตถูกสร้างอินสแตนซ์) มักจะค่อนข้างเจ็บปวดในการประกาศด้วยตนเอง


1
“ ตัวแปรเป็นแบบโลคัลสำหรับบล็อก” ซึ่งไม่เป็นความจริงเลย ตัวแปรทั้งหมดที่ประกาศในบล็อกเป็นแบบโลคัลของบล็อกนั้น (ตามขอบเขต) อาจมีการเชื่อมโยงกับตัวแปรอื่น ๆ ในโปรแกรม แต่การประกาศจะปรากฏในบล็อกนั้นเท่านั้น autoเป็นเรื่องเกี่ยวกับคลาสพื้นที่เก็บข้อมูลซึ่งไม่มีส่วนเกี่ยวข้องกับการมองเห็น
fuz

12

ด้วยคอมไพเลอร์ Aztec C แบบเก่ามันเป็นไปได้ที่จะเปลี่ยนตัวแปรอัตโนมัติทั้งหมดให้เป็นตัวแปรคงที่ (เพื่อเพิ่มความเร็วในการกำหนดแอดเดรส) โดยใช้สวิตช์บรรทัดคำสั่ง

แต่ตัวแปรที่ประกาศไว้อย่างชัดเจนautoถูกปล่อยทิ้งไว้ตามที่เป็นอยู่ในกรณีนั้น (จำเป็นสำหรับฟังก์ชันเรียกซ้ำซึ่งจะทำงานไม่ถูกต้อง!)


7

autoคำหลักจะคล้ายกับการรวมของอัฒภาคในหลามมันก็จำเป็นโดยภาษาก่อนหน้า ( B) autoแต่นักพัฒนารู้ว่ามันเป็นสิ่งที่ซ้ำซ้อนเนื่องจากส่วนใหญ่เป็น

ฉันสงสัยว่ามันถูกทิ้งไว้เพื่อช่วยในการเปลี่ยนจาก B เป็น C ในระยะสั้นการใช้งานหนึ่งสำหรับความเข้ากันได้ของภาษา B

ตัวอย่างเช่นใน B และ 80 C:

/* The following function will print a non-negative number, n, to
   the base b, where 2<=b<=10.  This routine uses the fact that
   in the ASCII character set, the digits 0 to 9 have sequential
   code values.  */

printn(n, b) {
        extrn putchar;
        auto a;

        if (a = n / b)        /* assignment, not test for equality */
                printn(a, b); /* recursive */
        putchar(n % b + '0');
}

1

คำสำคัญอัตโนมัติคือคลาสพื้นที่จัดเก็บ (เทคนิคบางอย่างที่ตัดสินอายุการใช้งานของตัวแปรและสถานที่จัดเก็บ) มีลักษณะการทำงานที่ตัวแปรที่ทำโดย Help ของคำหลักนั้นมีอายุการใช้งาน (อายุการใช้งาน) อยู่ภายในวงเล็บปีกกาเท่านั้น

{
    auto int x=8;        
    printf("%d",x);  // here x is 8

    { 
        auto int x=3;
        printf("%d",x);  // here x is 3
    }              

    printf("%d",x);  // here x is 8
}          

1

autoสามารถใช้ได้กับตัวแปรที่กำหนดขอบเขตบล็อกเท่านั้น extern auto intเป็นขยะเนื่องจากคอมไพเลอร์ไม่สามารถระบุได้ว่าสิ่งนี้ใช้คำจำกัดความภายนอกหรือไม่หรือจะแทนที่ภายนอกด้วยคำจำกัดความอัตโนมัติ (อัตโนมัติและภายนอกก็มีระยะเวลาการจัดเก็บที่แตกต่างกันโดยสิ้นเชิงเช่นstatic auto intซึ่งเห็นได้ชัดว่าเป็นขยะด้วย) มันสามารถเลือกตีความแบบเดียวได้เสมอ แต่เลือกที่จะถือว่าเป็นข้อผิดพลาดแทน

มีคุณลักษณะหนึ่งที่มีautoให้และเปิดใช้งานกฎ 'everything is an int' ภายในฟังก์ชัน ซึ่งแตกต่างจากภายนอกของฟังก์ชันซึ่งa=3ถูกตีความว่าเป็นคำจำกัดความint a =3เนื่องจากไม่มีการกำหนดที่ขอบเขตไฟล์a=3เป็นข้อผิดพลาดภายในฟังก์ชันเนื่องจากเห็นได้ชัดว่าคอมไพเลอร์ตีความว่าเป็นการกำหนดให้กับตัวแปรภายนอกมากกว่าคำจำกัดความ (แม้ว่าจะมี จะไม่มีextern int aการประกาศไปข้างหน้าในการทำงานหรือในขอบเขตไฟล์) แต่ระบุเช่นstatic, const, volatileหรือautoจะบ่งบอกว่ามันคือความหมายและคอมไพเลอร์จะใช้เวลาเป็นคำนิยามยกเว้นautoไม่ได้มีผลข้างเคียงของ specifiers อื่น ๆ ดังนั้นจึงเป็นไปโดยปริยายauto a=3 auto int a = 3เป็นที่ยอมรับsigned a = 3มีผลเหมือนกันและunsigned a = 3เป็น int ที่ไม่ได้ลงนามเสมอ

โปรดทราบว่า ' autoไม่มีผลกระทบต่อว่าวัตถุจะถูกจัดสรรให้กับรีจิสเตอร์หรือไม่ (เว้นแต่คอมไพเลอร์บางตัวจะให้ความสนใจกับมัน แต่ดูเหมือนว่าไม่น่าเป็นไปได้)'


-1

ฉันแน่ใจว่าคุณคุ้นเคยกับตัวระบุคลาสพื้นที่เก็บข้อมูลใน C ซึ่ง ได้แก่ "extern" "static" "register" และ "auto" คำจำกัดความของ "auto" มีให้ในคำตอบอื่น ๆ ค่อนข้างมาก แต่นี่คือการใช้คีย์เวิร์ด "auto" ที่เป็นไปได้ซึ่งฉันไม่แน่ใจ แต่ฉันคิดว่ามันขึ้นอยู่กับคอมไพเลอร์ คุณจะเห็นว่าเกี่ยวกับตัวระบุคลาสพื้นที่จัดเก็บมีกฎอยู่ เราไม่สามารถใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัวสำหรับตัวแปรได้ นั่นคือเหตุผลที่ตัวแปรส่วนกลางแบบคงที่ไม่สามารถถูกแทนที่ได้ ดังนั้นจึงรู้จักเฉพาะไฟล์ของพวกเขา เมื่อคุณไปที่การตั้งค่าคอมไพเลอร์ของคุณคุณสามารถเปิดใช้แฟล็กการเพิ่มประสิทธิภาพเพื่อความเร็ว วิธีหนึ่งที่คอมไพเลอร์ปรับให้เหมาะสมคือ ค้นหาตัวแปรที่ไม่มีตัวระบุคลาสหน่วยเก็บข้อมูลจากนั้นทำการประเมินตามความพร้อมใช้งานของหน่วยความจำแคชและปัจจัยอื่น ๆ เพื่อดูว่าควรปฏิบัติต่อตัวแปรนั้นโดยใช้ตัวระบุรีจิสเตอร์หรือไม่ ทีนี้จะเกิดอะไรขึ้นถ้าเราต้องการเพิ่มประสิทธิภาพโค้ดของเราเพื่อความเร็วในขณะที่รู้ว่าตัวแปรเฉพาะในโปรแกรมของเราไม่สำคัญมากนักและเราไม่ต้องการให้คอมไพเลอร์พิจารณามันเป็นรีจิสเตอร์ด้วยซ้ำ แม้ว่าโดยการใส่ auto คอมไพเลอร์จะไม่สามารถเพิ่ม register specifier ให้กับตัวแปรได้เนื่องจากพิมพ์ "register auto int a;" หรือ "auto register int a;" ทำให้เกิดข้อผิดพลาดในการใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัว สรุปแล้วฉันคิดว่า auto สามารถห้ามไม่ให้คอมไพเลอร์ปฏิบัติต่อตัวแปรเป็นรีจิสเตอร์ผ่านการเพิ่มประสิทธิภาพ จะเป็นอย่างไรหากเราต้องการเพิ่มประสิทธิภาพโค้ดของเราเพื่อความเร็วในขณะที่รู้ว่าตัวแปรเฉพาะในโปรแกรมของเราไม่สำคัญมากนักและเราไม่ต้องการให้คอมไพเลอร์พิจารณาว่าเป็นรีจิสเตอร์ แม้ว่าโดยการใส่ auto คอมไพเลอร์จะไม่สามารถเพิ่ม register specifier ให้กับตัวแปรได้เนื่องจากพิมพ์ "register auto int a;" หรือ "auto register int a;" ทำให้เกิดข้อผิดพลาดในการใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัว สรุปแล้วฉันคิดว่า auto สามารถห้ามไม่ให้คอมไพเลอร์ปฏิบัติต่อตัวแปรเป็นรีจิสเตอร์ผ่านการเพิ่มประสิทธิภาพ จะเป็นอย่างไรหากเราต้องการเพิ่มประสิทธิภาพโค้ดของเราเพื่อความเร็วในขณะที่รู้ว่าตัวแปรเฉพาะในโปรแกรมของเรานั้นไม่สำคัญมากนักและเราไม่ต้องการให้คอมไพเลอร์พิจารณามันเป็นรีจิสเตอร์ด้วยซ้ำ แม้ว่าโดยการใส่ auto คอมไพเลอร์จะไม่สามารถเพิ่ม register specifier ให้กับตัวแปรได้เนื่องจากพิมพ์ "register auto int a;" หรือ "auto register int a;" ทำให้เกิดข้อผิดพลาดในการใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัว สรุปแล้วฉันคิดว่า auto สามารถห้ามไม่ให้คอมไพเลอร์ปฏิบัติต่อตัวแปรเป็นรีจิสเตอร์ผ่านการเพิ่มประสิทธิภาพ ทำให้เกิดข้อผิดพลาดในการใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัว สรุปแล้วฉันคิดว่า auto สามารถห้ามไม่ให้คอมไพเลอร์ปฏิบัติต่อตัวแปรเป็นรีจิสเตอร์ผ่านการเพิ่มประสิทธิภาพ ทำให้เกิดข้อผิดพลาดในการใช้ตัวระบุคลาสหน่วยเก็บข้อมูลหลายตัว สรุปแล้วฉันคิดว่า auto สามารถห้ามไม่ให้คอมไพเลอร์ปฏิบัติต่อตัวแปรเป็นรีจิสเตอร์ผ่านการเพิ่มประสิทธิภาพ

ทฤษฎีนี้ใช้ไม่ได้กับคอมไพเลอร์ GCC แต่ฉันไม่ได้ลองคอมไพเลอร์อื่น

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