Đã sửa đổi nhiều mảng ở phạm vi tệp


85

Tôi muốn tạo một mảng tĩnh không đổi để được sử dụng trong toàn bộ tệp triển khai Objective-C của mình, tương tự như một cái gì đó như thế này ở cấp cao nhất của tệp ".m" của tôi:

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

Tôi dự định sử dụng NUM_TYPESsau này trong tệp nên tôi muốn đặt nó vào một biến.

Tuy nhiên, khi tôi làm điều này, tôi gặp lỗi

"Các loại 'được sửa đổi khác nhau ở phạm vi tệp"

Tôi thu thập rằng điều này có thể liên quan đến kích thước mảng là một biến (Tôi không nhận được thông báo này khi tôi đặt một số nguyên theo nghĩa đen ở đó, chẳng hạn như static int types[4]).

Tôi muốn sửa lỗi này, nhưng có lẽ tôi đã làm sai ... Tôi có 2 mục tiêu ở đây:

  1. Để có một mảng có thể truy cập được trong toàn bộ tệp
  2. Để đóng gói NUM_TYPESthành một biến để tôi không có cùng một chữ nằm rải rác ở các vị trí khác nhau trong tệp của mình

Bất kỳ đề xuất?

[EDIT] Tìm thấy điều này trong C FAQ: http://c-faq.com/ansi/constasconst.html


2
Điều gì xảy ra nếu bạn làm nó như một định nghĩa thay thế? #define kNUM_TYPES 4?
Jorge Israel Peña

Điều đó hoạt động ... vì một số lý do tôi đã cố gắng tránh sử dụng bộ tiền xử lý vì tôi nghĩ rằng tôi nhớ đã đọc nó ở đâu đó, nhưng tôi chỉ thực hiện thêm một số nghiên cứu và không thể tìm thấy lý do chính đáng để không sử dụng nó trong trường hợp này. Tôi nghĩ có thể ít mong muốn hơn nếu tôi đang tạo các đối tượng trong bộ tiền xử lý (như @"An NSString literal") Điều duy nhất sai với đoạn mã của bạn là không cần dấu chấm phẩy.
Sam

À vâng, cảm ơn bạn đã quan tâm và rất vui vì tôi có thể giúp đỡ.
Jorge Israel Peña,

Câu trả lời:


62

Lý do cho cảnh báo này là const trong c không có nghĩa là hằng số. Nó có nghĩa là "chỉ đọc". Vì vậy, giá trị được lưu trữ tại địa chỉ bộ nhớ và có thể bị thay đổi bởi mã máy.


3
Sửa đổi một đối tượng được xác định const(chẳng hạn như bằng cách truyền consttừ con trỏ và lưu trữ một giá trị) là hành vi không xác định; do đó, giá trị của một đối tượng như vậy là hằng số thời gian biên dịch hoặc thời gian chạy (tùy thuộc vào thời lượng lưu trữ). Giá trị không thể được sử dụng trong một biểu thức hằng đơn giản vì tiêu chuẩn C không nói rằng nó có thể được. (Đúc đi constvà lưu trữ một giá trị được phép nếu đối tượng đích được định nghĩa mà không consthoặc cấp phát động; xâu không constnhưng có thể không được ghi vào.)
jilles

3
@jilles "có khả năng bị thay đổi bằng mã máy" không có nghĩa là tác giả của câu trả lời này có nghĩa là "có khả năng bị thay đổi bởi mã C". Hơn nữa, điều này còn có một lý do rất chính đáng khác: có thể có các externhằng số trong các TU khác nhau mà giá trị không được biết khi biên dịch TU hiện tại.

14
Một cách để cải thiện câu trả lời này là chỉ ra cách giải quyết vấn đề này.
George Stocker

32

Nếu bạn vẫn sử dụng bộ tiền xử lý, theo các câu trả lời khác, thì bạn có thể làm cho trình biên dịch xác định giá trị của NUM_TYPEStự động:

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

Wow thật là tuyệt ... Tôi không biết điều đó có thể xảy ra. Tôi cho rằng chi phí tính toán này là không đáng kể. Tôi cũng có thể giả định rằng một trình biên dịch có thể tối ưu hóa điều này thành một giá trị tĩnh?
Sam

2
Có, kết quả của sizeofcác đối tượng như vậy là một hằng số thời gian biên dịch.
caf


11

Cũng có thể sử dụng phép liệt kê.

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

4

Như nó đã được giải thích trong các câu trả lời khác, consttrong C chỉ có nghĩa là một biến ở chế độ chỉ đọc. Nó vẫn là một giá trị thời gian chạy. Tuy nhiên, bạn có thể sử dụng một enumhằng số thực trong C:

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

3

Imho đây là một lỗ hổng trong nhiều trình biên dịch c. Tôi biết thực tế là các trình biên dịch mà tôi đã làm việc không lưu trữ biến "const static" tại một địa chỉ mà thay thế việc sử dụng trong mã bằng chính hằng số. Điều này có thể được xác minh vì bạn sẽ nhận được cùng một tổng kiểm tra cho mã đã tạo khi bạn sử dụng chỉ thị #define tiền xử lý và khi bạn sử dụng biến const tĩnh.

Dù bằng cách nào, bạn nên sử dụng biến const tĩnh thay vì #defines bất cứ khi nào có thể vì const tĩnh là kiểu an toàn.


Điều đó nghe có vẻ khá tệ, vì bạn có thể lấy địa chỉ của một static constbiến. Hành vi bạn đang mô tả có thể là một tối ưu hóa hợp lệ, nhưng chắc chắn không phải là thứ luôn có thể hoạt động.
thư giãn

Nó thực sự ổn. Trình biên dịch C có thể thay thế việc sử dụng riêng lẻ các biến toàn cục const bằng giá trị không đổi nếu có thể. Nếu tất cả các tham chiếu đến một biến được chuyển đổi thành hằng số, thì trình biên dịch có thể loại bỏ nó hoàn toàn. Nếu bạn sử dụng địa chỉ ở bất kỳ đâu, nó sẽ không bị xóa. Không có điều gì thay đổi rằng theo tiêu chuẩn ngôn ngữ, C không cho phép các mảng toàn cục với một biến là kích thước, cho dù biến đó có phải là const hay không.
Evan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.