Array modificato in modo variabile nell'ambito del file


87

Voglio creare un array statico costante da utilizzare in tutto il mio file di implementazione Objective-C simile a qualcosa di simile al livello superiore del mio file ".m":

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

Ho intenzione di utilizzarlo in NUM_TYPESseguito nel file, quindi ho voluto inserirlo in una variabile.

Tuttavia, quando lo faccio, ottengo l'errore

"Tipi" modificati in modo variabile nell'ambito del file "

Capisco che questo potrebbe avere qualcosa a che fare con la dimensione dell'array che è una variabile (non ricevo questo messaggio quando metto un intero letterale lì, come static int types[4]).

Voglio risolvere questo problema, ma forse sto sbagliando tutto ... Ho 2 obiettivi qui:

  1. Per avere un array accessibile in tutto il file
  2. Per incapsulare NUM_TYPESin una variabile in modo da non avere lo stesso letterale sparso in punti diversi nel mio file

Eventuali suggerimenti?

[EDIT] Trovato in C Faq: http://c-faq.com/ansi/constasconst.html


2
Cosa succede se invece lo fai come una definizione? #define kNUM_TYPES 4?
Jorge Israel Peña

Funziona ... per qualche motivo stavo cercando di evitare di usare il preprocessore perché pensavo di ricordarmi di averlo letto da qualche parte, ma ho solo fatto qualche ricerca in più e non sono riuscito a trovare una buona ragione per non usarlo in questo caso. Penso che potrebbe essere meno desiderabile se sto creando oggetti nel preprocessore (come @"An NSString literal") L'unica cosa che non va con il tuo pezzo di codice è che non c'è bisogno del punto e virgola.
Sam

Ah sì, grazie per l'avvertimento e sono contento di aver potuto aiutare.
Jorge Israel Peña

Risposte:


63

La ragione di questo avviso è che const in c non significa costante. Significa "sola lettura". Quindi il valore viene memorizzato in un indirizzo di memoria e potrebbe essere potenzialmente modificato dal codice macchina.


3
La modifica di un oggetto definito const(ad esempio il lancio constda un puntatore e la memorizzazione di un valore) è un comportamento indefinito; pertanto, il valore di un tale oggetto è una costante in fase di compilazione o di esecuzione (a seconda della durata della memorizzazione). Il valore non può essere utilizzato in un'espressione costante semplicemente perché lo standard C non dice che può esserlo. (L'eliminazione conste la memorizzazione di un valore è consentita se l'oggetto di destinazione è definito senza consto allocato dinamicamente; le stringhe letterali non sono constma non possono essere scritte.)
jilles

3
@jilles "potrebbe potenzialmente essere modificato dal codice macchina" non significa che l'autore di questa risposta intendesse "potrebbe potenzialmente essere modificato dal codice C". Inoltre, questo ha un altro ottimo motivo: possono esserci externcostanti in diverse TU di cui non si conosce il valore quando si compila la TU corrente.

15
Un modo per migliorare questa risposta sarebbe mostrare come risolvere questo problema.
George Stocker

33

Se intendi comunque utilizzare il preprocessore, come per le altre risposte, puoi fare in modo che il compilatore determini il valore di NUM_TYPESautomagicamente:

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

Wow, è davvero fantastico ... Non sapevo che fosse possibile. Presumo che il costo di questo calcolo sia trascurabile. Potrei anche presumere che un compilatore possa ottimizzarlo a un valore statico?
Sam

2
Sì, il risultato di sizeofoggetti come questo è una costante del tempo di compilazione.
caf


11

È anche possibile utilizzare l'enumerazione.

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

4

Come è già spiegato in altre risposte, constin C significa semplicemente che una variabile è di sola lettura. È ancora un valore di runtime. Tuttavia, puoi usare un enumcome costante reale in C:

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

3

Imho questo è un difetto in molti compilatori C. So per certo che i compilatori con cui ho lavorato non memorizzano una variabile "const statica" in un indirizzo, ma sostituiscono l'uso nel codice con la stessa costante. Ciò può essere verificato poiché si otterrà lo stesso checksum per il codice prodotto quando si utilizza una direttiva #define per i preprocessori e quando si utilizza una variabile const statica.

In entrambi i casi dovresti usare le variabili const statiche invece di #defines quando possibile poiché la const statica è indipendente dai tipi.


Sembra piuttosto brutto, dal momento che puoi prendere l'indirizzo di una static constvariabile. Il comportamento che stai descrivendo potrebbe essere un'ottimizzazione valida, ma certamente non è qualcosa che potrebbe sempre funzionare.
rilassarsi

In realtà va bene. Va bene che il compilatore C sostituisca gli usi individuali delle variabili globali const con il valore costante ove possibile. Se tutti i riferimenti a una variabile vengono convertiti in costanti, il compilatore può rimuoverla completamente. Se utilizzi l'indirizzo ovunque, non verrà rimosso. Niente di tutto ciò cambia il fatto che, secondo lo standard del linguaggio, C non consente array globali con una variabile come dimensione, indipendentemente dal fatto che la variabile sia const o meno.
Evan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.