2015-06-01 17 views
5

Tak więc chcę mieć definicję rozmiaru tablicy w strukturze znanej w czasie kompilacji. Chciałbym również, aby ta liczba była dostępna jako zmienna, aby ułatwić późniejszy użytek. Oto, co mam:Wielkość elementu tablicy struct w oparciu o const int w plikach

To działa dobrze. Jednakże, jeśli mam go w pliku .h, który jest zawarty w wielu miejscach, kompilator narzeka na redefinicję BANANA_ARRAY_SIZE (co ma sens). Muszę więc zadeklarować to jako element zewnętrzny, dzięki czemu wiele jednostek kompilacji może o tym wiedzieć.

Więc teraz mam

extern const int BANANA_ARRAY_SIZE; 

typedef struct 
{ 
    //.. same as before 
} banana_struct; 

oraz w pliku wdrażania mam

const int BANANA_ARRAY_SIZE = 10; 

Ale teraz kompilator nie pozwoli mi zdefiniować struct już ze skargami

fields must have a constant size: variable length array in structure 

Czy istnieje sposób, w jaki mogę osiągnąć to, co chcę (mieć długość tablicy przechowywanej w zmiennej i użyć do zdefiniowania struct)?

Edit:

W odpowiedzi na sugestie, aby zamiast wykorzystywać #define s, Wolałbym nie.

Moje pytanie dotyczy tego, jak zachować tę stałą wartość w zmiennej, a także do ustawienia długości tablicy w strukturze. Jeśli potrzebujesz dalszego uzasadnienia, załóżmy, że potrzebuję funkcji, która pobiera wskaźnik do int. Nie można odwołać się do # definicji.

+1

Oczywiście można wykonać tylko ten rodzaj inicjowania w zasięgu lokalnym w zakresie C, a nie w zasięgu globalnym, który próbujesz. *** [ref] (http://stackoverflow.com/a/11541168/645128) *** iw tym samym poście: *** [ref2] (http://stackoverflow.com/a/11542474/645128) *** – ryyker

+0

Proszę przeczytać mój zaktualizowany komentarz, ostatni komentarz do mojej odpowiedzi. To się nie zdarza dla mnie _gcc-5.1.0_. –

+3

'#define BANANA_ARRAY_SIZE 10'' char bananas [BANANA_ARRAY_SIZE]; const size_t length = BANANA_ARRAY_SIZE; ' – chux

Odpowiedz

7

W języku C const obiekt nie jest stała. Nie można jej użyć do deklarowania macierzy innej niż VLA. Twoja pierwsza deklaracja nie jest kompilowana w języku C, co sprawia, że ​​nie jest jasne, co masz na myśli przez "funkcje w porządku".

Zobacz tutaj po więcej szczegółów: Shall I prefer constants over defines?

W twoim przypadku są ograniczone do zarówno #define lub enum stałych. Jeśli chcesz utworzyć wskaźniki do tej wartości, musisz dodatkowo zadeklarować obiekt o tej samej wartości, globalnie lub lokalnie, w zależności od potrzeb. Ale nie będzie można go używać w deklaracjach macierzy innych niż VLA. Zamiast tego będziesz musiał użyć stałej #define lub enum. Na przykład.

// In .h file 
#define BANANA_ARRAY_SIZE 10 
extern const int BANANA_ARRAY_SIZE_OBJ; 

// In .c file 
const int BANANA_ARRAY_SIZE_OBJ = BANANA_ARRAY_SIZE; 
+0

Zastanawiam się, czy gcc nie jest zgodny ze specyfikacją w odniesieniu do tego, ponieważ: const int LEN = 12; char my_array [LEN]; int main() {my_array [0] = 'a'; return 0; } kompiluje dobrze ... W każdym razie, myślę, że zasadniczo "to nie może być wykonane zgodnie ze specyfikacją" w c. Dzięki za informację! – Phildo

+0

@Phildo: '-std = c99' lub' c11'? To nie jest "spec", ale standard. – Olaf

+0

@Phildo: To zdecydowanie niezgodne z wersją C. Czy na pewno kompilujesz w trybie C, a nie w C++? W języku C++ byłoby to zgodne z prawem. – AnT

0

Musisz użyć extern na to, więc nie się Redifined, i trzeba będzie zdefiniować go raz w jednym .c pliku.

Przykład

  1. header.h

    extern const int BANANA_ARRAY_SIZE; 
    
  2. main.c

    void banana(void); /* provide a prototype for `banana()' */ 
    /* A single definition */ 
    const int BANANA_ARRAY_SIZE = 10; 
    
    int main(void) 
    { 
        banana(); 
        return 0; 
    } 
    

To dla celów demonstracyjnych, nie tylko dodać prototypy w prawdziwym życiu, należy dbać o układ kodu źródłowego i upewnić się, że prototyp jest zgodny z definicji funkcji, itd.

  1. banan.c

    #include "header.h" 
    #include <stdio.h> 
    
    void banana(void) 
    { 
        printf("%d\n", BANANA_ARRAY_SIZE); 
    } 
    

Kompilacja z

gcc -Wall -Werror -o banana banana.c main.c  

gdy wykonywany będzie drukować 10.

Ale polecam makra zamiast, jak

#define BANANA_ARRAY_SIZE 10 

następnie można nawet zdefiniowane go w czasie kompilacji jak

gcc -DBANANA_ARRAY_SIZE=10 a.c b.c d.c -o executable 

aby zapobiec redefinicji lub brak definicji w ogóle wspólnego nagłówka plik będzie zawierał

#ifndef BANANA_ARRAY_SIZE 
#define BANANA_ARRAY_SIZE 10 
#endif 
+0

Co ty wypróbujesz co? to działa dla mnie! –

+0

Jak to się różni od tego, co ma OP? On wyraźnie wspomniał, że użył 'extern' w pliku nagłówkowym. definiowanie struct w pliku nagłówkowym z zachowaniem definicji 'BANANA_ARRAY_SIZE' w .c –

+0

Jestem świadomy używania extern.Mam to nawet w moim pytaniu.To pytanie brzmi" dlaczego nie mogę użyć wartości const extern do zdefiniowania długość tablicy? ". Zobacz także moja edycja: używająC#defines – Phildo

4

Można też użyć enum lub grupę #define

enum { 
BANANA_ARRAY_SIZE = 10 
}; 

lub

#define BANANA_ARRAY_SIZE 10 
0

Zgodnie z projektem C11 6.6 # 10, "Implementacja może akceptować inne formy wyrażeń stałych.".

Tried że z gcc 4.8.2:

static const size_t arr_size = 10; // static does not change anything 
static int arr[arr_size];   // dito 

gcc -std=gnu11 -Wall test.c 

test.c:6:12: error: variably modified ‘arr’ at file scope 
static int arr[arr_size]; 

Tak, że nie działa (byłby zaskoczony, gdyby miał mnie). Nawet , jeśli zadziałałby identyfikator, byłaby zdefiniowana implementacja i może zmieniać się nawet między dwiema łatkami dla tego samego kompilatora.

Istnieje wyraźna przyczyna nie działa, expecially jeśli const ma zasięg globalny: Jeśli moduł jest kompilowany, który zawiera nagłówek z deklaracją, kompilator nie ma możliwości knwo rzeczywistą wartość tego stała zmienna (!).Więc w jaki sposób mógłby zarezerwować miejsce dla tablicy w sekcji .bss lub móc sprawdzić zakresy, jeśli podano inicjatory (i przydzielić miejsce w sekcji .data)? Wymagałoby to interwencji linkera i miałoby znacznie większy wpływ na inicjalizatory, itp. Jestem pewien, że żaden kompilator nie zaakceptuje tego z podanych powodów.


Tak, trzeba uciekać się do korzystania #define:

"array.h": 
#define MAX_ARR_LEN 10 
extern const size_t max_arr_len; 

"array.c": 
const size_t max_arr_len = 10; 

Uwaga: Należy używać size_t za granice tablicy. Po to właśnie jest (między innymi).