2015-06-01 24 views
5

Vì vậy, tôi muốn có một định nghĩa về kích thước của một mảng trong một cấu trúc được biết đến tại thời gian biên dịch. Tôi cũng muốn số đó có sẵn dưới dạng biến để dễ sử dụng sau này. Những gì tôi có là như sau:cấu trúc mảng thành viên kích thước dựa trên const int trên các tập tin

const int BANANA_ARRAY_SIZE = 10; 

typedef struct 
{ 
    char bananas[BANANA_ARRAY_SIZE]; 
    int some_other_stuff; 
} banana_struct; 

Chức năng này tốt. Tuy nhiên, nếu tôi có nó trong một tập tin .h được bao gồm trong nhiều nơi, trình biên dịch than phiền về định nghĩa lại của BANANA_ARRAY_SIZE (có ý nghĩa). Vì vậy, tôi cần phải khai báo nó như là một extern để nhiều đơn vị biên dịch có thể biết về nó.

Vì vậy, bây giờ tôi có

extern const int BANANA_ARRAY_SIZE; 

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

và trong một tập tin thực hiện Tôi có

const int BANANA_ARRAY_SIZE = 10; 

Nhưng bây giờ các trình biên dịch sẽ không cho phép tôi xác định struct nữa với khiếu nại của

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

Có cách nào tôi có thể đạt được những gì tôi muốn (có chiều dài của mảng được lưu trữ trong biến và được sử dụng để xác định struct)?

Edit:

Để đối phó với những gợi ý để thay vì sử dụng #define s, tôi không muốn.

Câu hỏi của tôi là về cách có giá trị không đổi này được lưu trữ trong một biến và cũng được sử dụng để đặt độ dài của một mảng trong cấu trúc. Nếu bạn cần biện minh thêm, giả sử tôi cần một hàm nhận một con trỏ tới một int. Không thể tham chiếu của #define.

+1

Bạn rõ ràng chỉ có thể thực hiện loại khởi tạo này trong phạm vi địa phương trong C, chứ không phải phạm vi toàn cầu mà bạn đang cố gắng thực hiện. *** [ref] (http://stackoverflow.com/a/11541168/645128) *** và trong cùng một bài đăng: *** [ref2] (http://stackoverflow.com/a/11542474/645128) *** – ryyker

+0

Vui lòng đọc nhận xét cập nhật của tôi, nhận xét cuối cùng về câu trả lời của tôi. Nó không xảy ra với tôi _gcc-5.1.0_. –

+3

'#define BANANA_ARRAY_SIZE 10'' char chuối [BANANA_ARRAY_SIZE]; const size_t length = BANANA_ARRAY_SIZE; ' – chux

Trả lời

7

Trong ngôn ngữ C const đối tượng không phải là một liên tục. Bạn không thể sử dụng nó để khai báo một mảng không phải VLA. Khai báo đầu tiên của bạn không phải là compilable trong ngôn ngữ C, mà làm cho nó không rõ ràng những gì bạn có nghĩa là bởi "chức năng tốt".

Xem ở đây để biết thêm chi tiết: Shall I prefer constants over defines?

Trong trường hợp của bạn, bạn bị hạn chế hoặc #define hoặc enum hằng số. Nếu bạn cũng muốn tạo con trỏ đến giá trị đó, bạn sẽ phải khai báo thêm một đối tượng const với cùng giá trị, toàn cục hoặc cục bộ nếu cần. Nhưng bạn sẽ không thể sử dụng nó trong các khai báo mảng không phải VLA. Thay vào đó, bạn sẽ phải sử dụng hằng số #define hoặc enum. Ví dụ.

// 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

Tôi tự hỏi, nếu gcc không phải là spec tương ứng đối với điều đó, như sau: const int LEN = 12; char my_array [LEN]; int main() {my_array [0] = 'a'; trả về 0; } biên dịch tiền phạt ... Dù sao thì, tôi đoán rằng về cơ bản "điều này không thể thực hiện theo thông số kỹ thuật" trong c. Cảm ơn bạn về thông tin! – Phildo

+0

@Phiên bản: '-std = c99' hoặc' c11'? Nó không phải là "spec", nhưng là tiêu chuẩn. – Olaf

+0

@Phiên bản: Điều đó chắc chắn không tuân thủ trong bất kỳ phiên bản nào của C. Bạn có chắc là bạn đang biên dịch trong chế độ C và không ở chế độ C++? Trong C++ sẽ hợp pháp. – AnT

0

Bạn phải sử dụng extern để làm điều đó, vì vậy, không phải được đổi màu và bạn sẽ cần xác định nó một lần trong một tệp .c.

Ví dụ

  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; 
    } 
    

này là dành cho mục đích trình diễn, bạn không chỉ cần thêm các nguyên mẫu trong cuộc sống thực, bạn phải quan tâm đến cách bố trí mã nguồn và đảm bảo rằng các nguyên mẫu phù hợp với định nghĩa chức năng, vv

  1. chuối.c

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

Biên soạn với

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

khi thực hiện sẽ in 10.

Nhưng tôi muốn giới thiệu một macro thay vào đó, như

#define BANANA_ARRAY_SIZE 10 

sau đó bạn thậm chí có thể định nghĩa nó tại thời gian biên dịch như

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

để ngăn chặn sự tái định nghĩa hoặc không có định nghĩa nào cả một tiêu đề chung tệp sẽ chứa

#ifndef BANANA_ARRAY_SIZE 
#define BANANA_ARRAY_SIZE 10 
#endif 
+0

Bạn thử cái gì? Nó hoạt động cho tôi! –

+0

Điều này khác gì với những gì OP có? Anh ta đã đề cập một cách rõ ràng rằng anh ta đã sử dụng 'extern' trong tệp tiêu đề. xác định cấu trúc trong tệp tiêu đề trong khi vẫn giữ định nghĩa 'BANANA_ARRAY_SIZE' trong .c –

+0

Tôi biết sử dụng extern. Tôi thậm chí còn có câu hỏi đó. Câu hỏi đặt ra là" tại sao tôi không thể sử dụng giá trị const bên ngoài để xác định chiều dài của mảng? ". Ngoài ra, hãy xem bản chỉnh sửa của tôi: sử dụng #defines – Phildo

4

Bạn có thể có thể sử dụng một enum hoặc một #define

enum { 
BANANA_ARRAY_SIZE = 10 
}; 

hoặc

#define BANANA_ARRAY_SIZE 10 
0

Theo dự thảo C11 6.6 # 10, "Triển khai có thể chấp nhận các dạng biểu thức không đổi khác".

Cố gắng rằng với 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]; 

Vì vậy, điều đó không làm việc (sẽ ngạc nhiên với tôi nếu nó có). Ngay cả nếu id hoạt động, nó sẽ được thực hiện được xác định và có thể thay đổi ngay cả giữa hai bản vá cho cùng một trình biên dịch.

Có một lý do rõ ràng cho điều này không làm việc, expecially nếu const có phạm vi toàn cầu: Nếu một mô-đun được biên soạn bao gồm các tiêu đề với việc kê khai, trình biên dịch không có cách nào để knwo thực tế giá trị của rằng biến số không đổi (!).Vì vậy, làm thế nào nó sẽ dành không gian cho mảng trong phần .bss hoặc có thể kiểm tra phạm vi nếu initializers được đưa ra (và phân bổ không gian trong phần .data)? Điều đó đòi hỏi sự can thiệp của trình liên kết và sẽ có tác động nhiều hơn đến các bộ khởi tạo, vv Tôi chắc chắn rằng không có trình biên dịch nào chấp nhận điều này vì các lý do được đưa ra.


Vì vậy, bạn phải nghỉ mát để sử dụng #define:

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

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

Lưu ý: sử dụng size_t cho mảng giới hạn. Đó là những gì nó là cho (trong số những người khác).

Các vấn đề liên quan