Pertanyaan Mengapa int x [n] salah di mana n adalah nilai konstitusi?


Saya tidak mengerti mengapa melakukan ini salah:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

meskipun n sudah menjadi nilai konstanta.

Saat melakukan hal ini tampaknya tepat untuk kompilator GNU:

const int n = 5;
int x[n]; /*without initialization*/

Saya sadar fitur VLA C99 dan saya pikir itu terkait dengan apa yang terjadi tetapi Saya hanya perlu klarifikasi tentang apa yang terjadi di latar belakang.


37
2018-02-02 19:19


asal


Jawaban:


Hal utama yang perlu diingat adalah itu const dan "konstan" berarti dua hal yang sangat berbeda.

Itu const kata kunci benar-benar berarti "hanya-baca". SEBUAH konstan adalah literal numerik, seperti 42 atau 1.5 (atau enumerasi atau karakter konstan). SEBUAH ekspresi konstan adalah jenis ekspresi tertentu yang dapat dievaluasi pada waktu kompilasi, seperti 2 + 2.

Jadi diberi deklarasi:

const int n = 5;

ekspresi n mengacu pada nilai dari obyek, dan itu tidak diperlakukan sebagai ekspresi konstan. Kompiler tipikal akan mengoptimalkan referensi n, menggantinya dengan kode yang sama yang akan digunakan untuk literal 5, tetapi itu tidak diperlukan - dan aturan untuk apakah ekspresi itu konstan ditentukan oleh bahasa, bukan oleh kepandaian kompiler saat ini.

Contoh perbedaan antara const (hanya-baca) dan konstan (dievaluasi pada waktu kompilasi) adalah:

const size_t now = time(NULL);

Itu const kata kunci berarti Anda tidak diizinkan untuk mengubah nilai now setelah inisialisasi, tetapi nilai time(NULL) jelas tidak dapat dihitung hingga waktu berjalan.

Jadi ini:

const int n = 5;
int x[n];

tidak lebih valid dalam C daripada tanpa const kata kunci.

Bahasa bisa (dan IMHO mungkin) mengevaluasi n sebagai ekspresi konstan; itu tidak didefinisikan seperti itu. (C ++ memang memiliki aturan seperti itu; lihat standar C ++ atau referensi yang layak untuk detail yang mengerikan.)

Jika Anda menginginkan konstanta bernama dengan nilai 5, cara yang paling umum adalah mendefinisikan makro:

#define N 5
int x[N];

Pendekatan lain adalah mendefinisikan konstanta enumerasi:

enum { n = 5 };
int x[n];

Konstanta enumerasi adalah ekspresi konstan, dan selalu bertipe int (yang berarti metode ini tidak akan berfungsi untuk jenis selain int). Dan itu bisa dibilang penyalahgunaan dari enum mekanisme.

Dimulai dengan standar 1999, array dapat didefinisikan dengan ukuran tidak konstan; ini adalah VLA, atau larik dengan panjang variabel. Array tersebut diizinkan hanya pada lingkup blok, dan mungkin tidak memiliki initializers (karena compiler tidak dapat memeriksa bahwa initializer memiliki jumlah elemen yang benar).

Tetapi mengingat kode asli Anda:

const int n = 5; 
int x[n] = { 1,1,3,4,5 };

Anda dapat membiarkan kompilator menyimpulkan panjang dari penginisialisasi:

int x[] = { 1,1,3,4,5 };

Dan Anda kemudian dapat menghitung panjang dari ukuran larik:

const int x_len = sizeof x / sizeof x[0];

35
2018-02-02 21:43



Mengapa int x[n] salah di mana n adalah const nilai?

n bukan sebuah konstanta. const hanya berjanji itu n adalah variabel 'hanya-baca' yang tidak boleh dimodifikasi selama pelaksanaan program.
Perhatikan bahwa dalam tidak seperti , const variabel yang memenuhi syarat tidak konstan. Oleh karena itu, array yang dideklarasikan adalah array panjang variabel.
Anda tidak dapat menggunakan daftar initializer untuk menginisialisasi array panjang variabel.

C11-§6.7.9 / 3:

Jenis entitas yang akan diinisialisasi adalah array yang tidak diketahui ukurannya atau jenis objek lengkap yang ada bukan jenis array panjang variabel.

Kamu dapat memakai #define atau enum untuk membuat n sebuah konstanta

#define n 5
int x[n] = { 1,1,3,4,5 };   

21
2018-02-02 19:20



Jika Anda secara mendalam memulai suatu array, maka itu lebih mudah, lebih aman dan lebih mudah dipertahankan untuk membiarkan compiler menyimpulkan ukuran array:

int x[] = { 1,1,3,4,5 };
const int n = sizeof(x) / sizeof(*x) ; 

Kemudian untuk mengubah ukuran larik, Anda hanya perlu mengubah jumlah penginisialisasi, daripada mengubah ukurannya dan daftar inisialisasi untuk dicocokkan. Sangat berguna ketika ada banyak penginisialisasi.


7
2018-02-02 20:15



Meskipun n adalah const, Anda tidak dapat menggunakannya untuk menentukan ukuran array kecuali Anda ingin membuat VLA. Namun, Anda tidak dapat menggunakan daftar penginisialisasi untuk menginisialisasi VLA.

Gunakan makro untuk membuat array ukuran tetap.

#define ARRAY_SIZE 5

int x[ARRAY_SIZE] = { 1,1,3,4,5 };

3
2018-02-02 19:23



Apakah kode Anda secara semantik berbeda dari myfunc() sini:

void myfunc(const int n) { 
    int x[n] = { 1,1,3,4,5 };
    printf("%d\n", x[n-1]);
    *( (int *) &n) = 17;    //  Somewhat less "constant" than hoped...
    return ;
}

int main(){
    myfunc(4);
    myfunc(5);
    myfunc(6);  //  Haven't actually tested this.  Boom?  Maybe just printf(noise)?
    return 0;
}

Aku s n benar-benar semua yang konstan? Berapa banyak ruang yang menurut Anda harus dialokasikan oleh kompilator x[] (Karena ini pekerjaan kompilator untuk melakukannya)?

Seperti yang orang lain tunjukkan, cv-kualifikasi const tidak tidak berarti "nilai yang konstan selama kompilasi dan untuk setiap saat setelah". Ini berarti "nilai yang tidak seharusnya diubah oleh kode lokal (meskipun bisa)".


2
2018-02-03 13:43