it-swarm-id.com

Deklarasi variabel dalam file header - statis atau tidak?

Saat refactoring, beberapa #defines Saya menemukan deklarasi yang mirip dengan yang berikut dalam file header C++:

static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;

Pertanyaannya adalah, apa bedanya, jika ada, yang akan dibuat oleh statis? Perhatikan bahwa beberapa pemasukan header tidak dimungkinkan karena klasik #ifndef HEADER#define HEADER#endif trik (jika itu penting).

Apakah statis berarti hanya satu salinan VAL dibuat, jika header disertakan oleh lebih dari satu file sumber?

86
Rob

static berarti bahwa akan ada satu salinan VAL yang dibuat untuk setiap file sumber yang disertakan. Tetapi itu juga berarti bahwa banyak inklusi tidak akan menghasilkan banyak definisi VAL yang akan bertabrakan pada waktu tautan. Dalam C, tanpa static Anda harus memastikan bahwa hanya satu file sumber yang ditentukan VAL sementara file sumber lain menyatakannya extern. Biasanya orang akan melakukan ini dengan mendefinisikannya (mungkin dengan inisialisasi) dalam file sumber dan meletakkan deklarasi extern dalam file header.

static variabel di tingkat global hanya terlihat di file sumber mereka sendiri apakah mereka sampai di sana melalui sebuah menyertakan atau berada di file utama.


Catatan editor: Dalam C++, const objek tanpa static atau extern kata kunci dalam deklarasi mereka secara implisit static.

102
Justsalt

Tag static dan extern pada variabel lingkup file menentukan apakah mereka dapat diakses di unit terjemahan lain (mis. Lainnya .c atau .cpp file).

  • static memberikan tautan internal variabel, menyembunyikannya dari unit terjemahan lain. Namun, variabel dengan tautan internal dapat didefinisikan dalam beberapa unit terjemahan.

  • extern memberikan hubungan eksternal variabel, membuatnya terlihat oleh unit terjemahan lainnya. Biasanya ini berarti bahwa variabel hanya harus didefinisikan dalam satu unit terjemahan.

Defaultnya (ketika Anda tidak menentukan static atau extern) adalah salah satu area di mana C dan C++ berbeda.

  • Dalam C, variabel yang dicakup file adalah extern (hubungan eksternal) secara default. Jika Anda menggunakan C, VAL adalah static dan ANOTHER_VAL adalah extern.

  • Dalam C++, variabel yang dicakup file adalah static (hubungan internal) secara default jika mereka const, dan extern secara default jika tidak. Jika Anda menggunakan C++, baik VAL dan ANOTHER_VAL adalah static.

Dari konsep spesifikasi C :

6.2.2 Keterkaitan pengidentifikasi ... -5- Jika deklarasi pengidentifikasi untuk suatu fungsi tidak memiliki specifier kelas penyimpanan, keterkaitannya ditentukan persis seolah-olah dideklarasikan dengan extern specifier kelas penyimpanan. Jika deklarasi pengidentifikasi untuk objek memiliki cakupan file dan tidak ada specifier kelas penyimpanan, hubungannya adalah eksternal.

Dari konsep spesifikasi C++ :

7.1.1 - Penentu kelas penyimpanan [dcl.stc] ... -6- Sebuah nama yang dideklarasikan dalam ruang lingkup namespace tanpa penentu-kelas-penyimpanan memiliki hubungan eksternal kecuali memiliki hubungan internal karena deklarasi sebelumnya dan asalkan tidak menyatakan const. Objek yang dinyatakan const dan tidak secara eksplisit menyatakan eksternal memiliki hubungan internal.

107
bk1e

Statis akan berarti Anda mendapatkan satu salinan per file, tetapi tidak seperti yang lain mengatakan itu sah untuk melakukannya. Anda dapat dengan mudah menguji ini dengan contoh kode kecil:

test.h:

static int TEST = 0;
void test();

test1.cpp:

#include <iostream>
#include "test.h"

int main(void) {
    std::cout << &TEST << std::endl;
    test();
}

test2.cpp:

#include <iostream>
#include "test.h"

void test() {
    std::cout << &TEST << std::endl;
}

Menjalankan ini memberi Anda output ini:

0x446020
0x446040

46
slicedlime

const variabel dalam C++ memiliki hubungan internal. Jadi, menggunakan static tidak berpengaruh.

a.h

const int i = 10;

one.cpp

#include "a.h"

func()
{
   cout << i;
}

two.cpp

#include "a.h"

func1()
{
   cout << i;
}

Jika ini adalah program C, Anda akan mendapatkan kesalahan 'beberapa definisi' untuk i (karena tautan eksternal).

6
Nitin

Deklarasi statis pada level kode ini berarti bahwa variabel hanya terlihat di unit kompilasi saat ini. Ini berarti bahwa hanya kode dalam modul yang akan melihat variabel itu.

jika Anda memiliki file header yang menyatakan variabel statis dan header itu dimasukkan dalam beberapa file C/CPP, maka variabel itu akan menjadi "lokal" untuk modul-modul tersebut. Akan ada N salinan variabel itu untuk header N tempat yang disertakan. Mereka tidak berhubungan satu sama lain sama sekali. Kode apa pun dalam salah satu file sumber itu hanya akan merujuk variabel yang dideklarasikan dalam modul itu.

Dalam kasus khusus ini, kata kunci 'statis' tampaknya tidak memberikan manfaat apa pun. Saya mungkin melewatkan sesuatu, tetapi tampaknya tidak masalah - saya belum pernah melihat yang dilakukan seperti ini sebelumnya.

Adapun inlining, dalam hal ini variabel kemungkinan digarisbawahi, tapi itu hanya karena itu dinyatakan const. Compiler mungkin lebih cenderung inline variabel statis modul, tapi itu tergantung pada situasi dan kode yang dikompilasi. Tidak ada jaminan bahwa kompiler akan memberikan 'statika'.

5
Mark

Untuk menjawab pertanyaan, "apakah statis berarti hanya satu salinan VAL yang dibuat, jika header disertakan oleh lebih dari satu file sumber?" ...

NO . VAL akan selalu ditentukan secara terpisah di setiap file yang termasuk header.

Standar untuk C dan C++ memang menyebabkan perbedaan dalam hal ini.

Di C, variabel file-lingkup adalah eksternal secara default. Jika Anda menggunakan C, VAL bersifat statis dan ANOTHER_VAL adalah eksternal.

Perhatikan bahwa tautan modern dapat mengeluh tentang ANOTHER_VAL jika header disertakan dalam file yang berbeda (nama global yang sama didefinisikan dua kali), dan pasti akan mengeluh jika ANOTHER_VAL diinisialisasi ke nilai yang berbeda di file lain

Dalam C++, variabel file-lingkup adalah statis secara default jika mereka adalah const, dan extern secara default jika mereka tidak. Jika Anda menggunakan C++, VAL dan ANOTHER_VAL keduanya statis.

Anda juga perlu memperhitungkan fakta bahwa kedua variabel tersebut ditunjuk sebagai konst. Idealnya kompiler akan selalu memilih untuk memasukkan variabel-variabel ini dan tidak menyertakan penyimpanan apa pun untuk mereka. Ada sejumlah alasan mengapa penyimpanan dapat dialokasikan. Yang bisa saya pikirkan ...

  • opsi debug
  • alamat diambil dalam file
  • kompiler selalu mengalokasikan penyimpanan (tipe const yang kompleks tidak dapat dengan mudah digariskan, sehingga menjadi kasus khusus untuk tipe dasar)
2
itj

Buku C (online gratis) memiliki bab tentang tautan, yang menjelaskan arti 'statis' lebih terinci (walaupun jawaban yang benar sudah diberikan dalam komentar lain): http://publications.gbdirect.co .uk/c_book/chapter4/linkage.html

2
Jan de Vos

Anda tidak dapat mendeklarasikan variabel statis tanpa mendefinisikannya juga (ini karena pengubah kelas penyimpanan statis dan eksternal saling terpisah). Variabel statis dapat didefinisikan dalam file header, tetapi ini akan menyebabkan setiap file sumber yang menyertakan file header memiliki salinan variabelnya sendiri, yang mungkin bukan yang dimaksudkan.

2
Gajendra Kumar

Dengan asumsi bahwa deklarasi ini berada di lingkup global (mis. Bukan variabel anggota), maka:

statis berarti 'hubungan internal'. Dalam hal ini, karena dideklarasikan const ini dapat dioptimalkan/diuraikan oleh kompiler. Jika Anda menghilangkan const maka kompiler harus mengalokasikan penyimpanan di setiap unit kompilasi.

Dengan menghilangkan statis tautannya adalah extern secara default. Sekali lagi, Anda telah diselamatkan oleh const ness - kompiler dapat mengoptimalkan/inline penggunaan. Jika Anda menjatuhkan const maka Anda akan mendapatkan simbol yang didefinisikan berlipat ganda pada waktu tautan.

1
Seb Rose

const variabel secara default statis di C++, tetapi extern C. Jadi jika Anda menggunakan C++ ini tidak masuk akal konstruksi apa yang digunakan.

(7.11.6 C++ 2003, dan Apexndix C memiliki sampel)

Contoh dalam membandingkan sumber kompilasi/tautan sebagai program C dan C++:

bruziuz:~/test$ cat a.c
const int b = 22;
int main(){return 0;}
bruziuz:~/test$ cat b.c
const int b=2;
bruziuz:~/test$ gcc -x c -std=c89 a.c b.c
/tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b'
/tmp/ccDSd0V3.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status
bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c 
bruziuz:~/test$ 
bruziuz:~/test$ gcc --version | head -n1
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
1
bruziuz

Statis mencegah unit kompilasi lain mengeluarkan variabel itu sehingga kompiler dapat "inline" nilai variabel di mana ia digunakan dan tidak membuat penyimpanan memori untuk itu.

Dalam contoh kedua Anda, kompiler tidak dapat mengasumsikan bahwa beberapa file sumber lain tidak akan mengeksternasinya, sehingga ia harus benar-benar menyimpan nilai itu di memori di suatu tempat.

0
Jim Buck