Array yang dimodifikasi secara bervariasi pada ruang lingkup file

87

Saya ingin membuat array statis konstan untuk digunakan di seluruh file implementasi Objective-C saya mirip dengan sesuatu seperti ini di tingkat atas file ".m" saya:

static const int NUM_TYPES = 4;
static int types[NUM_TYPES] = { 
  1,
  2, 
  3, 
  4 };

Saya berencana untuk menggunakannya NUM_TYPESnanti di file jadi saya ingin memasukkannya ke dalam variabel.

Namun, ketika saya melakukan ini, saya mendapatkan kesalahan

"'Jenis' yang dimodifikasi secara bervariasi pada cakupan file"

Saya mengumpulkan bahwa ini mungkin ada hubungannya dengan ukuran array menjadi variabel (saya tidak mendapatkan pesan ini ketika saya meletakkan literal integer di sana, seperti static int types[4]).

Saya ingin memperbaikinya, tetapi mungkin saya melakukan semuanya dengan salah ... Saya punya 2 tujuan di sini:

  1. Untuk memiliki sebuah array yang dapat diakses di seluruh file
  2. Untuk mengenkapsulasi NUM_TYPESmenjadi variabel sehingga saya tidak memiliki literal yang sama yang tersebar di berbagai tempat di file saya

Ada saran?

[EDIT] Temukan ini di C Faq: http://c-faq.com/ansi/constasconst.html

Sam
sumber
2
Apa yang terjadi jika Anda melakukannya sebagai definisi? #define kNUM_TYPES 4?
Jorge Israel Peña
Itu berhasil ... untuk beberapa alasan saya mencoba menjauh dari menggunakan preprocessor karena saya pikir saya ingat pernah membacanya di suatu tempat, tetapi saya hanya melakukan beberapa penelitian lagi dan tidak dapat menemukan alasan yang baik untuk tidak menggunakannya dalam kasus ini. Saya pikir mungkin kurang diinginkan jika saya membuat objek di preprocessor (seperti @"An NSString literal") Satu-satunya hal yang salah dengan potongan kode Anda adalah bahwa tidak perlu titik koma.
Sam
Ah ya, terima kasih atas perhatiannya, dan senang bisa membantu.
Jorge Israel Peña

Jawaban:

63

Alasan peringatan ini adalah bahwa const dalam c tidak berarti konstan. Artinya "hanya baca". Jadi nilainya disimpan di alamat memori dan berpotensi dapat diubah oleh kode mesin.

larsr
sumber
3
Memodifikasi objek yang ditentukan const(seperti dengan membuang constpenunjuk dan menyimpan nilai) adalah perilaku yang tidak ditentukan; oleh karena itu, nilai objek semacam itu adalah waktu kompilasi atau konstanta run-time (bergantung pada durasi penyimpanan). Nilai tidak dapat digunakan dalam ekspresi konstan hanya karena standar C tidak menyatakan dapat. (Membuang constdan menyimpan nilai diizinkan jika objek tujuan ditentukan tanpa constatau dialokasikan secara dinamis; string literal tidak consttetapi tidak boleh ditulis.)
jilles
3
@jilles "berpotensi dapat diubah oleh kode mesin" tidak berarti bahwa penulis jawaban ini berarti "berpotensi diubah oleh kode C". Selain itu, ini memang memiliki alasan lain yang sangat bagus: mungkin terdapat externkonstanta di TU berbeda yang nilainya tidak diketahui saat menyusun TU saat ini.
15
Cara untuk meningkatkan jawaban ini adalah dengan menunjukkan cara mengatasi masalah ini.
George Stocker
33

Jika Anda tetap akan menggunakan preprocessor, seperti jawaban lainnya, maka Anda dapat membuat compiler menentukan nilai secara NUM_TYPESotomatis:

#define NUM_TYPES (sizeof types / sizeof types[0])
static int types[] = { 
  1,
  2, 
  3, 
  4 };
kafe
sumber
Wow itu sangat keren ... Saya tidak tahu itu mungkin. Saya berasumsi bahwa biaya penghitungan ini dapat diabaikan. Mungkinkah saya juga berasumsi bahwa kompiler dapat mengoptimalkan ini menjadi nilai statis?
Sam
2
Ya, hasil dari sizeofobjek seperti itu adalah konstanta waktu kompilasi.
kafe
21
#define NUM_TYPES 4
Jim Buck
sumber
11

Dimungkinkan juga untuk menggunakan pencacahan.

typedef enum {
    typeNo1 = 1,
    typeNo2,
    typeNo3,
    typeNo4,
    NumOfTypes = typeNo4
}  TypeOfSomething;
Dave L Delaney
sumber
4

Seperti yang sudah dijelaskan di jawaban lain, constdi C hanya berarti variabel read-only. Ini masih merupakan nilai run-time. Namun, Anda dapat menggunakan enumkonstanta nyata di C:

enum { NUM_TYPES = 4 };
static int types[NUM_TYPES] = { 
  1, 2, 3, 4
};
CygnusX1
sumber
3

Imho ini adalah cacat di banyak kompiler c. Saya tahu pasti bahwa kompiler saya bekerja dengan tidak menyimpan variabel "konstanta statis" di alamat tetapi mengganti penggunaan dalam kode dengan sangat konstan. Ini dapat diverifikasi karena Anda akan mendapatkan checksum yang sama untuk kode yang dihasilkan saat Anda menggunakan arahan preprocessor #define dan saat Anda menggunakan variabel konstanta statis.

Anda harus menggunakan variabel konstanta statis daripada #defines jika memungkinkan karena konstanta statis bertipe aman.

hans lepoeter
sumber
Kedengarannya sangat buruk, karena Anda dapat mengambil alamat static constvariabel. Perilaku yang Anda gambarkan mungkin merupakan pengoptimalan yang valid, tetapi itu jelas bukan sesuatu yang selalu berhasil.
bersantai
Sebenarnya baik-baik saja. Tidak masalah bagi compiler C untuk mengganti penggunaan individual variabel global const dengan nilai konstan jika memungkinkan. Jika semua referensi ke variabel diubah menjadi konstanta, maka compiler dapat menghapusnya seluruhnya. Jika Anda menggunakan alamat di mana pun, alamat itu tidak akan dihapus. Tak satu pun dari perubahan itu yang menurut standar bahasa, C tidak mengizinkan array global dengan variabel sebagai ukurannya, apakah variabel itu konstan atau tidak.
Evan