Mengapa auto a = 1; kompilasi dalam C?

125

Kode:

int main(void)
{
    auto a=1;
    return 0;
}

dikompilasi tanpa kesalahan oleh kompiler MS Visual Studio 2012, ketika file tersebut memiliki ekstensi .c. Saya selalu berpikir bahwa ketika Anda menggunakan ekstensi .c, kompilasi harus sesuai dengan sintaks C, dan bukan C ++. Selain itu, sejauh yang saya tahu otomatis tanpa jenis hanya diperbolehkan di C ++ sejak C ++ 11, di mana itu berarti bahwa jenis tersebut disimpulkan dari penginisialisasi.

Apakah itu berarti bahwa kompiler saya tidak menempel ke C, atau kode sebenarnya benar dalam bahasa C?

lee77
sumber
8
Baik Anda mengkompilasi dengan mode C ++ (mungkin) atau MS masih terjebak dalam milenium terakhir. Tersirat inttelah dihapus dari standar C pada tahun 1999.
Jens Gustedt
16
@JensGustedt MSVC ++ hanya mendukung C89 (dan beberapa fitur dari C99). Ini lebih dari kompiler C ++.
ntoskrnl
3
@Brandin: Dengan opsi / Wall memberi peringatan C4431, mengatakan bahwa specifier tipe tidak ada dan int default tidak lagi didukung di C (lihat komentar Jens '). Ini sedikit kontradiksi karena jelas kompiler ini mendukungnya ...
lee77
4
@JensGustedt Dengan ukuran itu, GCC 4.7, dirilis 2012, (dan versi yang lebih baru juga, saya kira - saya tidak memilikinya) juga "macet dalam milenium terakhir". Ini mengkompilasi kode OP bahkan tanpa pemberitahuan ketika tidak diberi bendera apa pun.
3
@nannan, saya kira setidaknya, bahwa OP telah mengaktifkan tingkat peringatan. Jelas saya salah. Dan dalam arti ini benar, gcc juga masih terjebak di sana, karena mereka masih tidak memiliki C99 (atau varian) sebagai default. dentang memperingatkan tentang konstruk, bahkan tanpa bendera.
Jens Gustedt

Jawaban:

240

autoadalah kata kunci C lama yang berarti "ruang lingkup lokal". auto asama dengan auto int a, dan karena cakupan lokal adalah default untuk variabel yang dideklarasikan di dalam suatu fungsi, itu juga sama seperti int adalam contoh ini.

Kata kunci ini sebenarnya adalah sisa dari pendahulu C, di mana tidak ada tipe dasar: semuanya int, penunjuk int, array int. (*) Deklarasi akan berupa autoatau extrn[sic]. C mewarisi "semuanya int" sebagai aturan default, jadi Anda bisa mendeklarasikan bilangan bulat dengan

auto a;
extern b;
static c;

ISO C menyingkirkan ini, tetapi banyak kompiler masih menerimanya untuk kompatibilitas mundur. Jika tampaknya tidak dikenal, maka Anda harus menyadari bahwa aturan terkait sedang bekerja di

unsigned d;  // actually unsigned int

yang masih umum dalam kode modern.

C ++ 11 menggunakan kembali kata kunci, yang hanya sedikit jika ada programmer C ++ yang menggunakan makna aslinya, untuk inferensi tipenya. Ini sebagian besar aman karena aturan "semuanya int" dari C sudah dijatuhkan di C ++ 98; satu-satunya hal yang rusak adalah auto T a, yang tidak ada yang menggunakan pula. (Di suatu tempat di makalahnya tentang sejarah bahasa , Stroustrup berkomentar tentang ini, tapi saya tidak dapat menemukan referensi yang tepat sekarang.)

(*) Penanganan string dalam B menarik: Anda akan menggunakan array intdan mengemas beberapa karakter di setiap anggota. B sebenarnya BCPL dengan sintaks yang berbeda.

Fred Foo
sumber
7
Tidak, ini bukan C legal sejak 1999. Tidak ada kompiler C modern yang layak mengizinkan ini.
Jens Gustedt
18
@JensGustedt VS tidak mengklaim untuk menyediakan kompiler C modern. Dari semua penampilan, kerja pada kompiler C berhenti bertahun-tahun yang lalu; mereka hanya menyediakannya sehingga orang dapat terus mengkompilasi kode warisan. (Dan tentu saja, setiap kompiler C modern yang layak akan memiliki opsi untuk mendukung kode lawas. Termasuk opsi untuk K&R C.)
James Kanze
23
@JensGustedt: Anda yakin? GCC dan Dentang keduanya memperingatkan tentang hal itu dalam mode C99, tetapi mereka tidak menganggapnya sebagai kesalahan kecuali dengan -Werror.
Fred Foo
2
@ Larsman, ya, dalam 6.7.2 ada batasan eksplisit untuk itu: Setidaknya satu jenis specifier akan diberikan dalam penspesifikasi deklarasi di setiap deklarasi ...
Jens Gustedt
40
@JensGustedt - re Tidak, ini bukan hukum C sejak 1999. Tidak ada kompiler C modern yang layak untuk ini Pernyataan pertama benar; itu ilegal sejak 1999. IMHO, pernyataan kedua tidak benar. Kompiler C modern mana pun yang layak harus mengizinkan hal ini. Lihatlah semua kode lawas yang harus ditulis ulang jika mereka tidak mengizinkannya. Saya telah menulis jawaban yang memperluas komentar ini.
David Hammen
35

Ini adalah jawaban dan komentar tambahan untuk Tidak, ini bukan C hukum sejak 1999. Tidak ada kompiler C modern yang layak memungkinkan untuk ini.

Ya, auto a=1;ilegal di C1999 (dan juga C2011). Hanya karena ini sekarang ilegal tidak berarti bahwa kompiler C modern harus menolak kode yang mengandung konstruksi tersebut. Saya berpendapat sebaliknya, bahwa kompiler C modern yang layak masih harus memungkinkan untuk ini.

Baik dentang dan gcc melakukan hal itu ketika mengkompilasi kode sampel dalam pertanyaan terhadap versi 1999 atau 2011 standar. Kedua penyusun mengeluarkan diagnostik dan kemudian melanjutkan seolah-olah pernyataan keberatan telah auto int a=1;.

Menurut pendapat saya, inilah yang harus dilakukan oleh kompiler yang layak. Dengan mengeluarkan diagnostik, dentang dan gcc sepenuhnya sesuai dengan standar. Standar tidak mengatakan bahwa kompilator harus menolak kode ilegal. Standar hanya mengatakan bahwa implementasi yang sesuai harus menghasilkan setidaknya satu pesan diagnostik jika unit terjemahan berisi pelanggaran terhadap aturan atau batasan sintaksis apapun (5.1.1.3).

Kode yang diberikan yang mengandung konstruksi ilegal, setiap kompiler yang layak akan mencoba memahami kode ilegal sehingga kompiler dapat menemukan kesalahan berikutnya dalam kode. Kompiler yang berhenti pada kesalahan pertama bukanlah kompiler yang sangat baik. Ada cara untuk masuk akal auto a=1, yaitu menerapkan aturan "int implisit". Aturan ini memaksa kompiler untuk menginterpretasikan auto a=1seolah-olah auto int a=1ketika kompiler digunakan dalam mode C90 atau K&R.

Sebagian besar kompiler biasanya menolak kode (tolak: menolak untuk membuat file objek atau file yang dapat dieksekusi) yang berisi sintaksis ilegal. Ini adalah kasus di mana penulis kompiler memutuskan bahwa gagal mengkompilasi bukan pilihan terbaik. Hal terbaik untuk dilakukan adalah mengeluarkan diagnostik, memperbaiki kode, dan melanjutkan. Terlalu banyak kode lawas yang dibumbui dengan konstruksi seperti register a=1;. Kompiler harus dapat mengkompilasi kode itu dalam mode C99 atau C11 (dengan diagnostik, tentu saja).

David Hammen
sumber
1
@ Larsmans - Saya bisa melihat dari mana Anda berasal. Anda ingin -ffs-please-stop-allowing-constructs-from-some-previous-millenniumopsi kompiler, atau lebih tepatnya, -fstrict-complianceopsi. Menggerutu pada kompiler: "Ketika saya menggunakan -std = c11, saya tidak berharap bahwa kruft K&R kuno untuk dikompilasi. Bahkan, saya ingin itu tidak dikompilasi!"
David Hammen
1
Sebenarnya tidak ada, saya mau harus mengubah pada bendera untuk mendapatkan cruft terburuk untuk kompilasi. Tetapi -std=c99menjadi lebih ketat akan menjadi langkah ke arah yang benar :)
Fred Foo
1
Jika Anda menggunakan gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror(yang saya gunakan secara rutin, bahkan pada kode dari pertanyaan pada SO), maka Anda mendapatkan cukup dekat dengan apa yang Anda inginkan. Saya ingin GCC default ke setidaknya -std=c99dan lebih disukai -std=c11(atau, -std=gnu11mereka lebih cenderung melakukan itu), tetapi sampai saat itu, ... Anda dapat mengubah opsi tersebut; -pedantic, -Wshadow, -Wold-style-declarationDan beberapa orang lain dapat berguna, tapi ini adalah awal yang baik mengatur pilihan.
Jonathan Leffler
3
@DavidHammen: Baik kompleksitas siklomatik, manajer proyek, maupun kebijakan perusahaan adalah elemen bahasa.
Jerry B
3
Bendera untuk mendapatkan perilaku yang Anda inginkan di GCC adalah-pedantic-errors
τεκ
29

automemiliki makna di dalam Cdan C++sebelum Standar 2011. Ini berarti bahwa variabel memiliki masa pakai otomatis, yaitu, masa pakai yang ditentukan oleh cakupan . Ini bertentangan dengan, misalnya, staticseumur hidup, di mana variabel berlangsung "selamanya", terlepas dari ruang lingkupnya. autoadalah masa hidup standar, dan hampir tidak pernah dieja secara eksplisit. Inilah sebabnya mengapa aman untuk mengubah artinya C++.

Sekarang C, sebelum Standar 99, jika Anda tidak menentukan jenis variabel, standarnya adalah int.

Jadi dengan auto a = 1;Anda mendeklarasikan (dan mendefinisikan) suatu intvariabel, dengan masa pakai ditentukan oleh cakupan.

("Seumur hidup" lebih tepat disebut "durasi penyimpanan", tapi saya pikir itu mungkin kurang jelas).

BoBTFish
sumber
Oke, jadi sebenarnya a = 1 otomatis diizinkan dalam C dan berarti variabel int dengan durasi penyimpanan otomatis.
lee77
1
Benar, "durasi penyimpanan" mengambil salah satu dari daftar nilai, "otomatis", "statis", "dinamis", "utas". "Seumur Hidup" adalah waktu sebenarnya dari kehidupan objek. Jadi variabel memiliki durasi penyimpanan "otomatis" dan seumur hidup "durasi ruang lingkup mainfungsi".
Steve Jessop
@Steve ya, saya tidak bermaksud mengatakan itu autodan statichanya dua kemungkinan. Saya mencoba untuk menulis jawaban saya dengan cara yang ditargetkan pada penanya, yang tampaknya cukup baru untuk C++(dan C), jadi saya sedikit menyelimuti detailnya. Mungkin itu ide yang buruk; mereka perlu ditutup cepat atau lambat.
BoBTFish
1
@ BoBTFish: oh, saya tidak mengeluh tentang itu. Saya hanya bermaksud memperluas perbedaan semantik antara "seumur hidup", yang merupakan durasi, dan "durasi penyimpanan" yang mungkin lebih akurat disebut "kategori durasi penyimpanan".
Steve Jessop
Hal tersirat intini dihapus dari C sejak 1999.
Jens Gustedt
8

Dalam C, dan dialek historis C ++, autoadalah makna kata kunci yang amemiliki penyimpanan otomatis. Karena hanya dapat diterapkan ke variabel lokal, yang otomatis secara default, tidak ada yang menggunakannya; itulah sebabnya C ++ kini telah menggunakan kembali kata kunci.

Secara historis, C telah memungkinkan deklarasi variabel tanpa specifier tipe; tipe default untuk int. Jadi deklarasi ini setara dengan

int a=1;

Saya pikir ini sudah usang (dan mungkin dilarang) dalam C modern; tetapi beberapa kompiler populer default ke C90 (yang, saya pikir, mengizinkannya), dan, yang mengganggu, hanya mengaktifkan peringatan jika Anda secara spesifik memintanya. Mengkompilasi dengan GCC dan menentukan C99 dengan -std=c99, atau mengaktifkan peringatan dengan -Wallatau -Wimplicit-int, memberikan peringatan:

warning: type defaults to int in declaration of a
Mike Seymour
sumber
4
Memang dilarang di C sejak 1999.
Jens Gustedt
5

Dalam C, autoberarti hal yang sama registertidak di C ++ 11: itu berarti bahwa suatu variabel memiliki durasi penyimpanan otomatis.

Dan di C sebelum C99 (dan kompiler Microsoft tidak mendukung C99 atau C11, meskipun mungkin mendukung bagian-bagian itu), tipe ini dapat dihilangkan dalam banyak kasus, di mana ia akan default int.

Tidak mengambil tipe dari initialiser sama sekali. Anda baru saja memilih penginisialisasi yang kompatibel.


sumber
1
Bukankah kata kunci register tidak digunakan lagi dalam C ++ 11?
kotor
@sordid Ya, benar. Sebelum C ++ 11, autodan registermemiliki arti yang sama persis (saya sebelumnya berkomentar bahwa ada batasan untuk mengambil registeralamat variabel-kualifikasi, tapi itu tidak benar untuk C ++). register, sementara sudah tidak digunakan lagi, tetap mempertahankan makna lamanya untuk saat ini.
5
@JensGustedt: Jawabannya tidak mengatakan itu. Ia mengatakan bahwa autodi C berarti sama dengan registerdi C ++, yang artinya (keduanya berarti durasi penyimpanan otomatis, dan tidak ada yang lain).
Mike Seymour
3

Jenis kompilasi studio visual tersedia di right click on file -> Properties -> C/C++ -> Advanced -> Compile As. Untuk memastikan itu dikompilasi sebagai /TCopsi C force. Maka dalam hal ini adalah apa yang dikatakan larsmans ( autokata kunci C lama ). Mungkin dikompilasi sebagai C ++ tanpa Anda sadari.

UmNyobe
sumber
3

Kelas penyimpanan mendefinisikan ruang lingkup (visibilitas) dan masa hidup variabel dan / atau fungsi dalam Program C.

Ada kelas penyimpanan berikut yang dapat digunakan dalam Program C.

auto
register
static
extern

auto adalah kelas penyimpanan default untuk semua variabel lokal.

{
        int Count;
        auto int Month;
}

Contoh di atas mendefinisikan dua variabel dengan kelas penyimpanan yang sama. otomatis hanya dapat digunakan dalam fungsi, yaitu variabel lokal.

intadalah tipe default untuk autokode di bawah ini:

auto Month;
/* Equals to */
int Month;

Kode di bawah ini juga legal:

/* Default-int */
main()
{
    reurn 0;
}
Amir Saniyan
sumber