2009-11-11 8 views
77

Chcę utworzyć stały statyczną tablicę być stosowane w całym moim pliku implementacji Objective-C podobny do czegoś takiego na najwyższym poziomie mojego „.m” file:Bezstopniowa zmodyfikowana tablica w zakresie plików

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

Mam zamiar później użyć pliku NUM_TYPES, więc chciałem umieścić go w zmiennej.

Jednak, kiedy to zrobić, pojawia się błąd

„Bezstopniowa zmodyfikowane«typy»w zakresie plików”

wnoszę, że może to mieć coś wspólnego z wielkością tablicy bycie zmienną (nie dostaję tej wiadomości, gdy umieszczam tam literał liczb całkowitych, np. static int types[4]).

chcę to naprawić, ale może ja będę o tym wszystkim nie tak ... Mam 2 goli tutaj:

  1. Aby mieć tablicę, który jest dostępny w całym pliku
  2. Do hermetyzacji NUM_TYPES do zmiennej, więc nie mam tego samego dosłownego rozrzuconego w różnych miejscach w moim pliku

Jakieś sugestie?

[EDIT] Znalazłem to w C FAQ: http://c-faq.com/ansi/constasconst.html

+2

Co stanie się, jeśli zrobisz to jako definicję? '#define kNUM_TYPES 4'? –

+0

To działa ...z jakiegoś powodu starałem się trzymać z daleka od używania preprocesora, ponieważ myślałem, że pamiętałem gdzieś to czytać, ale po prostu zrobiłem więcej badań i nie mogłem znaleźć dobrego powodu, aby nie używać go w tym przypadku. Myślę, że może być mniej pożądane, jeśli tworzę obiekty w preprocesorze (jak '@" literał NSString "') Jedyną rzeczą, która jest nie tak z twoim kawałkiem kodu jest to, że nie ma potrzeby używania średnika. – Sam

+0

Ach tak, dziękuję za wzniesione głowy i cieszę się, że mogłem pomóc. –

Odpowiedz

21
#define NUM_TYPES 4 
29

Jeśli masz zamiar użyć preprocesor i tak, jak w innych odpowiedzi, to można zrobić kompilator określenia wartości NUM_TYPES automagicznie:

#define NUM_TYPES (sizeof types/sizeof types[0]) 
static int types[] = { 
    1, 
    2, 
    3, 
    4 }; 
+0

Wow, to naprawdę fajne ... Nie wiedziałem, że to możliwe. Zakładam, że koszt tego obliczenia jest znikomy. Czy mogę też założyć, że kompilator może zoptymalizować to do wartości statycznej? – Sam

+2

Tak, wynikiem 'sizeof' na takich obiektach jest stała czasu kompilacji. – caf

12

Możliwe jest również użycie wyliczenia.

typedef enum { 
    typeNo1 = 1, 
    typeNo2, 
    typeNo3, 
    typeNo4, 
    NumOfTypes = typeNo4 
} TypeOfSomething; 
+1

To też zadziała, dzięki. – Sam

53

Powodem tego ostrzeżenia jest to, że const in c doesn't mean constant. It means "read only". więc wartość jest przechowywana w pamięci adres i potencjalnie mogą być zmieniane za pomocą kodu maszynowego.

+3

Modyfikowanie zdefiniowanego obiektu 'const' (na przykład przez odrzucenie' const' ze wskaźnika i zapisanie wartości) jest niezdefiniowanym zachowaniem; dlatego wartość takiego obiektu jest stała kompilacji lub czasu wykonywania (w zależności od czasu przechowywania). Wartości nie można używać w wyrażeniu stałym, ponieważ standard C nie mówi, że może być. (Odrzucanie 'const' i przechowywanie wartości jest dozwolone, jeśli obiekt docelowy jest zdefiniowany bez' const' lub dynamicznie przydzielany, literały łańcuchowe nie są 'const', ale nie mogą być zapisane.) – jilles

+3

@jilles" może potencjalnie zostać zmieniony przez kod maszynowy "nie oznacza, że ​​autor tej odpowiedzi oznaczał" mógł zostać zmieniony przez kod C ". Co więcej, ma to kolejny bardzo dobry powód: mogą występować stałe "zewnętrzne" w różnych JT, których wartość nie jest znana podczas kompilowania aktualnej JT. –

+7

Sposobem na poprawę tej odpowiedzi byłoby pokazanie, jak rozwiązać ten problem. –

4

Imho jest to usterka w wielu kompilatorach c. Wiem na pewno, że kompilatory, z którymi pracowałem, nie przechowują zmiennej "static const" na adresie, ale zastępują użycie w kodzie bardzo stałą. Można to zweryfikować, ponieważ otrzymasz tę samą sumę kontrolną dla wygenerowanego kodu, gdy użyjesz dyrektywy #define preprocesorów i gdy użyjesz statycznej zmiennej stałej.

W każdym razie powinieneś użyć statycznych zmiennych stałych zamiast #defines, gdy tylko jest to możliwe, ponieważ statyczna const jest bezpieczna.

+0

To brzmi dość źle, ponieważ możesz wziąć adres zmiennej 'static const'. Opisane zachowanie może być prawidłową optymalizacją, ale z pewnością nie jest to coś, co zawsze może działać. – unwind

+0

To jest w porządku. Kompilator języka C może zastąpić indywidualne użycie stałych zmiennych globalnych wartością stałą, gdy tylko jest to możliwe. Jeśli wszystkie odniesienia do zmiennej są konwertowane na stałe, wówczas kompilator może ją całkowicie usunąć. Jeśli użyjesz adresu w dowolnym miejscu, nie zostanie on usunięty. Żadna z tych zmian nie zmienia tego zgodnie ze standardem językowym, C nie zezwala na globalne tablice ze zmienną jako wielkością, niezależnie od tego, czy zmienna jest stała, czy nie. – Evan

3

Jak już wyjaśniono w innych odpowiedziach, const w C oznacza jedynie, że zmienna jest tylko do odczytu. Jest to nadal wartość czasu wykonywania. Można jednak użyć enum jako stałej rzeczywistej w C:

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