Mengapa C memungkinkan banyak deklarasi global dari variabel yang sama tetapi BUKAN beberapa deklarasi lokal?

8

Saya perhatikan bahwa jika saya mendeklarasikan variabel global beberapa kali, kompiler bahkan tidak mengeluarkan peringatan.

Namun jika saya mendeklarasikan variabel lokal dalam suatu fungsi beberapa kali, misalnya, kompiler gcc menghasilkan kesalahan dan tidak mengkompilasi file. (Saya bertanya dalam hal gcc, tapi ini lebih merupakan pertanyaan desain bahasa umum, bukan pertanyaan tentang gcc, karena saya pikir kemungkinan kompiler lain berperilaku serupa).

Apa penjelasan untuk perilaku ini?

yoyo_fun
sumber
Yang pasti, variabel global Anda, selalu bertipe sama, kan?
Walfrat
@ Walfrat Ya variabel selalu dideklarasikan dari tipe yang sama. Jika dua variabel dengan nama yang sama tetapi dengan jenis yang berbeda dideklarasikan secara global, kesalahan keluaran gcc "tipe yang
bertolak belakang
3
Anda tidak dapat mendeklarasikan variabel lokal sekalipun. Yang bisa Anda lakukan adalah mendefinisikannya. Mendeklarasikan variabel memberitahu kompiler apa itu. Mendefinisikan sebuah variabel memberitahu kompiler untuk mengalokasikan memori untuknya. Anda harus mendefinisikan semua variabel. Dalam C, definisi variabel global dapat digunakan untuk deklarasi beberapa kali. Tetapi jika program hanya memiliki extern int x;, yang merupakan deklarasi, kompilasi akan dibatalkan karena tidak ada tempat di mana memori dialokasikan ke variabel.
shawnhcorey

Jawaban:

11

Menurut pedoman pengkodean :

Dalam himpunan unit terjemahan dan perpustakaan yang merupakan keseluruhan program, setiap deklarasi pengidentifikasi tertentu dengan tautan eksternal menunjukkan objek atau fungsi yang sama. Dalam satu unit terjemahan, setiap deklarasi pengidentifikasi dengan tautan internal menunjukkan objek atau fungsi yang sama. Setiap pernyataan pengidentifikasi tanpa hubungan menunjukkan suatu entitas yang unik.

Variabel lokal tidak memiliki tautan. jadi ada nama Tabrakan terjadi. Jadi, beberapa deklarasi variabel lokal tidak mungkin.

Variabel global memiliki hubungan eksternal. Jadi, beberapa deklarasi variabel global dimungkinkan.

msc
sumber
7
Jawaban ini baik-baik saja, namun, pertanyaan tindak lanjut yang jelas kemudian adalah: apa alasan di balik definisi ini?
Doc Brown
Dengan banyak kebiasaan C, alasannya adalah "kompiler C pra-standar hanya melakukannya dengan cara ini". Jika Anda melihat kompleksitas "definisi sementara", kemungkinan besar inilah yang terjadi di sini.
Sebastian Redl
9

@msc memberikan pengantar yang baik tentang aturan di balik perilaku ini.

Saya perhatikan bahwa jika saya mendeklarasikan variabel global beberapa kali, kompiler bahkan tidak mengeluarkan peringatan.

C memiliki tiga jenis deklarasi global untuk objek, yaitu yang (dan saya paham di staticsini):

  1. deklarasi yang bukan definisi - extern int a;
  2. deklarasi yang juga definisi - int a = 3;atauextern int a = 3;
  3. definisi tentatif - int a;

Deklarasi berganda tipe 1 & 3 diizinkan, sementara paling banyak satu (tipe 2) definisi diizinkan.


Apa penjelasan untuk perilaku ini?

Jika Anda juga bertanya tentang motivasi untuk aturan ini, itu adalah dukungan untuk kompilasi terpisah . (Lihat unit terjemahan ).

Untuk memecah suatu program menjadi beberapa file yang dikompilasi secara terpisah, kita memerlukan beberapa fitur, yaitu (a) dapat mendeklarasikan tanpa harus mendefinisikan , dan, (b) meneruskan deklarasi .

Dalam satu unit terjemahan, kami harus dapat merujuk ke fungsi global dan data dalam unit terjemahan lain. Dan kami juga ingin memeriksa kesalahan, di sini, untuk menemukan definisi yang hilang, dan definisi duplikat yang salah.

Terkadang, di unit terjemahan yang sama, kami mendeklarasikan global, dan kemudian mendefinisikannya nanti. Ini dapat terjadi jika kita memerlukan deklarasi maju untuk beberapa alasan, atau jika kita menggunakan file header umum (yang menyediakan deklarasi) dalam satu unit terjemahan yang juga menawarkan definisi eksplisit.

Karena kompilasi terpisah dalam C berlaku dengan menghubungkan fungsi dan data global bersama-sama, fitur-fitur ini diperlukan di tingkat global tetapi tidak di tingkat lokal.

Seperti yang ditunjukkan oleh @msc, semua ini tidak diperlukan untuk variabel lokal karena mereka tidak memiliki tautan.

C (seperti banyak bahasa lain) tidak menyediakan keterkaitan untuk variabel lokal karena bahasa tidak berusaha untuk mendukung fungsi tunggal yang mencakup beberapa unit terjemahan terpisah.

(Tentu saja, Anda dapat memiliki fungsi span beberapa file sumber, tetapi tidak beberapa unit terjemahan.)

Definisi tentatif berfungsi seperti deklarasi karena diizinkan dalam beberapa unit terjemahan (dan juga menggabungkan dengan baik dengan deklarasi lain). Namun, jika tidak ada definisi (non-tentatif) untuk pengidentifikasi di seluruh program, himpunan (satu atau lebih) definisi tentatif di beberapa unit terjemahan (untuk satu pengidentifikasi) diambil sebagai definisi untuk objek yang penginisialisasinya adalah nol.

Ini dapat diimplementasikan dengan menempatkan ini ke dalam bagian .BSS dengan ukuran dan keselarasan yang tepat; linker akan mencocokkannya dengan definisi sebenarnya jika ditemukan, atau mencocokkannya satu sama lain, memberi mereka ruang kosong di BSS.


Gagasan kompilasi yang terpisah dapat didukung sepenuhnya tanpa fitur definisi tentatif - Saya pikir definisi tentatif ada sebagian besar karena alasan historis. (Saya tidak mengatakan mereka tidak berguna, hanya jika bahasa itu dibuat hari ini, ini mungkin dianggap tidak perlu dan karenanya tidak ditawarkan.)

Erik Eidt
sumber