2009-09-16 11 views
44

Sé que es bastante idiomático, o un buen estilo al menos, en C declarar constantes numéricas como enum s en lugar de #define ing them.¿Cómo declaras las constantes de cadena en C?

/* bad style */ 
#define MAXLINE 1024 

/* good/better style */ 
enum { 
    MAX_LINE = 1024 
}; 

¿Existe una regla equivalente para la definición de constantes de cadena?

/* is this good style? */ 
#define HELLO "Hello World" 

/* or is this better? */ 
const char *HELLO2 = "Howdy"; 

¿Qué prefieres? Si es posible, muestre algunos inconvenientes de cualquiera de los métodos.

Respuesta

70

Hay uno más (por lo menos) Camino a Roma:

static const char HELLO3[] = "Howdy"; 

(static - opcional - es para evitar que entren en conflicto con otros archivos). Preferiría este sobre const char*, porque entonces podrás usar sizeof(HELLO3) y por lo tanto no tienes que posponer hasta el tiempo de ejecución lo que puedes hacer en tiempo de compilación.

Sin embargo, la definición tiene una ventaja de la concatenación en tiempo de compilación (piense en HELLO ", World!") y puede sizeof(HELLO) también.

Pero también puede preferir const char* y usarlo en varios archivos, lo que le ahorraría un poco de memoria.

En resumen, depende.

+0

Gracias por su explicación. La razón para usar 'enum's en lugar de macro constantes o' const int' para valores enteros constantes es el hecho de que esta es la única forma segura de tipo para declarar un entero constante que puede ser portátil usado como un límite de matriz. Bueno ... La concatenación de cadenas de tiempo de compilación casi me vendió usando '# define's para cadenas, pero me atengo a' const char * 'para seguridad tipo usando' static' cuando corresponda. En resumen, usaré 'enum' para las constantes enteras y las variables' const' para todo el resto. –

+1

tatt, sugiero que no se apegue a nada. * No todas las constantes son iguales *. Si no vas a concatenar, no necesitas #define, si tampoco vas a necesitar el tamaño, no te importa en absoluto. Lo que no veo totalmente es cómo 'const char *' es mejor que 'const char []' * donde estática es aplicable *. Pero, de nuevo, si no necesita el tamaño, tampoco es peor ;-) –

9

Una ventaja (aunque muy leve) de la definición de cadena constantes es que se pueden concatenar:

 
#define HELLO "hello" 
#define WORLD "world" 

puts(HELLO WORLD); 

No estoy seguro de que eso es realmente una ventaja, pero es una técnica que no se pueden utilizar con const char * 's.

3

La principal desventaja del método #define es que la cadena se duplica cada vez que se usa, por lo que puede terminar con muchas copias en el ejecutable, lo que lo hace más grande.

+5

Creo que el compilador los optimizará al menos mientras se usen en el mismo archivo. Así que eso no es realmente "cada vez que se usa", pero sí, la definición de la constante global ahorra espacio a veces. –

+2

que es verdadero, a menos que el compilador o el enlazador colapsen las copias en una sola. Esta función también se denomina a veces "agrupación de cadenas" – Rom

-2

Para la primera. Los enteros son, por defecto, enteros, lo que significa que puede pasar ese valor solo a algo que solo acepta números enteros.

El segundo que más me gusta: la versión const char * en lugar de #define. La razón es que las matrices en c son punteros, lo que significa que cada vez que desee usar la versión #define, debe crear una instancia de esta cadena solo para usarla.

+1

las matrices no son punteros y no hay ningún concepto de "creación de instancias de cadena" cuando se trata de constante de cadena. Y si las matrices eran punteros, eso no significaba que la secuencia tuviera que ser instanciada incluso si existiera tal cosa ;-) –

+0

estaba hablando de constantes numéricas. Normalmente, las matrices se pasan como referencias Al menos no puedo encontrar otra forma de hacerlo. Entonces ¿Cuál es el retorno predeterminado en este caso? { const char * str1 = HELLO; const char * str1 = HELLO; return (str1 == str2); } –

+0

El valor de retorno depende de la implementación, pero (suponiendo que signifique str2 en la segunda asignación) la mayoría de las implementaciones devolverá verdadero; pruébelo, ambos punteros harán referencia a la misma cadena en el segmento de datos constantes. Pero este código no tiene nada que ver con las matrices, es un puntero simple. En cuanto a pasar matrices como puntero, eso no implica que las matrices * sean * punteros. 'int *' y 'int [2]' son tipos diferentes. Y no solo teóricamente: no se puede sensiblemente el puntero 'sizeof()', no se puede incrementar la matriz, etc. –

7

Si quieres un "const string" como su pregunta dice, realmente iría por la versión que se indique en su pregunta:

/* first version */ 
const char *HELLO2 = "Howdy"; 

Particularmente, yo evitaría:

/* second version */ 
const char HELLO2[] = "Howdy"; 

Motivo: El problema con la segunda versión es que el compilador hará una copia de toda la cadena "Howdy", MÁS esa cadena es modificable (por lo que en realidad no es const).

Por otro lado, la primera versión es una cadena const accesible por const puntero HELLO2, y no hay manera de que nadie pueda modificarla.

+5

Creo que 'const char * const HELLO2' es mejor ... – Shawn

Cuestiones relacionadas