Змінено змінений масив у діапазоні файлу


85

Я хочу створити постійний статичний масив, який буде використовуватись у всьому моєму файлі реалізації Objective-C, подібному до приблизно такого на верхньому рівні мого файлу ".m":

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

Я планую використовувати NUM_TYPESпізніше у файлі, тому я хотів помістити його у змінну.

Однак, коли я роблю це, я отримую помилку

"Змінено модифіковані" типи "в області файлу"

Я зрозумів, що це може мати щось спільне з розміром масиву, який є змінною (я не отримую цього повідомлення, коли поміщаю туди цілочисельний літерал, наприклад static int types[4]).

Я хочу це виправити, але, можливо, я все це роблю не так ... У мене тут 2 цілі:

  1. Мати масив, доступний у всьому файлі
  2. Інкапсулювати NUM_TYPESу змінну, щоб у мене не було однакових літералів, розкиданих по різних місцях у моєму файлі

Будь-які пропозиції?

[РЕДАКТУВАТИ] Це знайдено у C Faq: http://c-faq.com/ansi/constasconst.html


2
Що станеться, якщо замість цього зробити це як визначення? #define kNUM_TYPES 4?
Хорхе Ізраїль Пенья

Це працює ... я чомусь намагався уникати використання препроцесора, бо думав, що десь це пам’ятаю, але я просто зробив ще кілька досліджень і не зміг знайти вагому причину, щоб не використовувати його в цьому випадку. Я думаю, що це може бути менш бажаним, якщо я створюю об'єкти в препроцесорі (наприклад @"An NSString literal"). Єдине, що неправильно з вашим фрагментом коду, це те, що немає потреби в крапці з комою.
Сем

Ах, так, дякую за голови, і радий, що міг допомогти.
Хорхе Ізраїль Пенья

Відповіді:


62

Причиною цього попередження є те, що const у c не означає постійну. Це означає "лише для читання". Отже, значення зберігається за адресою пам'яті і може бути змінено машинним кодом.


3
Модифікація визначеного об'єкта const(наприклад, шляхом відкидання constвказівника та збереження значення) є невизначеною поведінкою; отже, значення такого об'єкта є константою часу компіляції або часу виконання (залежно від тривалості зберігання). Значення не може використовуватися в константному виразі просто тому, що стандарт C не говорить, що це може бути. (Відкидання constта збереження значення дозволяється, якщо цільовий об'єкт визначено без constабо динамічно розподілено; рядкові літерали не є, constале не можуть бути записані.)
jilles

3
@jilles "потенційно може бути змінено машинним кодом" не означає, що автор цієї відповіді мав на увазі "може потенційно змінити код C". Крім того, це має ще одну дуже вагому причину: externу різних ТУ можуть бути константи, значення яких невідомо при складанні поточного ТУ.

14
Шляхом покращення цієї відповіді було б показати, як вирішити цю проблему.
Джордж Стокер

32

Якщо ви все одно збираєтеся використовувати препроцесор, згідно з іншими відповідями, тоді ви можете змусити компілятор автоматично визначати значення NUM_TYPES:

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

Ого, це справді круто ... Я не знав, що це можливо. Я припускаю, що вартість цього обчислення незначна. Чи можу я також припустити, що компілятор міг би оптимізувати це до статичного значення?
Сем

2
Так, результатом таких sizeofоб'єктів є константа часу компіляції.
кафе


11

Також можна використовувати перерахування.

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

4

Як це вже пояснено в інших відповідях, constна мові C просто означає, що змінна доступна лише для читання. Це як і раніше значення часу виконання. Однак ви можете використовувати enumяк реальну константу в C:

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

3

Імхо, це недолік багатьох компіляторів c. Я точно знаю, що компілятори, з якими я працював, не зберігають змінну "static const" в адресі, а замінюють використання в коді самою константою. Це можна перевірити, оскільки ви отримаєте однакову контрольну суму для створеного коду, коли використовуєте директиву #define препроцесорів та коли використовуєте статичну змінну const.

У будь-якому випадку ви повинні використовувати статичні змінні const замість #defines, коли це можливо, оскільки статичний const є типовим.


Це звучить досить погано, оскільки ви можете взяти адресу static constзмінної. Можливо, поведінка, яку ви описуєте, є дійсною оптимізацією, але це, безумовно, не завжди може спрацювати.
розмотати

Це насправді добре. Добре, що компілятор C замінює окреме використання глобальних змінних const постійним значенням, де це можливо. Якщо всі посилання на змінну перетворюються на константи, то компілятор може її повністю видалити. Якщо ви де-небудь використовуєте адресу, вона не буде видалена. Жодне з цього не змінює, що відповідно до мовного стандарту, C не допускає глобальних масивів із змінною як розміром, незалежно від того, змінна є const чи ні.
Еван
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.