tags:

views:

604

answers:

5

I know it's quite idiomatic, or good style at least, in C to declare numeric constants as enums instead of #defineing them.

/* bad style */
#define MAXLINE 1024

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

Is there an equivalent rule for the definition of string constants?

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

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

What do you prefer? If possible show some drawbacks of either method.

A: 

One advantage (albeit very slight) of defining string constants is that you can concatenate them:

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

puts( HELLO WORLD );

Not sure that's really an advantage, but it is a technique that cannot be used with const char *'s.

William Pursell
I'd recommend `HELLO ", " WORLD "!"` ;)
Michael Krelin - hacker
A: 

The main disadvantage of the #define method is that the string is duplicated each time it is used, so you can end up with lots of copies of it in the executable, making it bigger.

rikh
I believe compiler will optimize them out at least as long as they're used in the same file. So that's not really "each time it is used", but yes, defining global constant does save space sometimes.
Michael Krelin - hacker
that is true, unless the compiler or linker collapses the copies into one. This feature is also sometimes called "string pooling"
Rom
+7  A: 

There's one more (at least) road to Rome:

static const char HELLO3[] = "Howdy";

(static — optional — is to prevent it from conflicting with other files). I'd prefer this one over const char*, because then you'll be able to use sizeof(HELLO3) and therefore you don't have to postpone till runtime what you can do at compile time.

The define has an advantage of compile-time concatenation, though (think HELLO ", World!") and you can sizeof(HELLO) as well.

But then you can also prefer const char* and use it across multiple files, which would save you a morsel of memory.

In short — it depends.

Michael Krelin - hacker
Thanks for your explanation. The reason to use `enum`s instead of macro constants or `const int` for constant integer values is the fact this is the only type-safe way to declare a constant integer which can be portable used as an array boundary. Well... The compile time string concatenation almost selled me on using `#define`s for strings but I'll stick to `const char*` for type safety using `static` where applicable. In short I'll use `enum` for integer constants and `const` variables for all the rest.
tatt, I'd suggest that you don't stick to anything. *Not all constants are equal*. If you're not going to concatenate, you don't need #define, if you're not going to need the size either, you don't care at all. What I totally fail to see is how `const char*` is better then `const char []` *where static is applicable*. But then again, if you don't need the size, it's not any worse either ;-)
Michael Krelin - hacker
A: 

For the first one. Enums are by default integers, that mean that you can pass that value only to shomething that exept integers only.

Second one I better like const char* version insted of #define. The reason is that arrays in c are pointers that mean that each time that you want to use #define version, you have to instantate this string just to use it.

ralu
arrays aren't pointers and there's no concept of "string instantiation" when it comes to string constant. And if arrays were pointers that wouldn't mean that the string has to be instantiated even there were such thing ;-)
Michael Krelin - hacker
he was talking about numeric constants.Arrays are ussualy passed as references At least i can not figure other way for doing so.So.What is default return in this case?{const char* str1=HELLO;const char* str1=HELLO;return ( str1 == str2);}
ralu
The return value is implementation dependent, but (assuming you meant str2 in second assignment) most implementations will return true - try it, both pointers will reference the same string in constant data segment. But this code has nothing to do with arrays, it's plain pointer. As for passing arrays as pointer, that doesn't imply that arrays *are* pointers. `int*` and `int[2]` are different types. And not only theoretically - you can't sensibly `sizeof()` pointer, you can't increment array, etc.
Michael Krelin - hacker
in C are arrays and pointers are indistigusable.definition whit [] ( int array[20] ) is just for memory allocation on stack.there is no type for array in C. Just the const define that there is no need for memory allocation on stack, becuase const is "read only".How can you support the claim that int* and int[2] are different types? (whit code example)
ralu
`int aa[15]; myfun(a,sizeof(a)/sizeof(*a));` -- you can do such arithmetics at compile-time. With `int *ap = (int*)calloc(10,sizeof(int));` you can't determine the size without prior knowledge, i.e. repeating `10` part. You can `++ap`, you can't `++aa`. These *are* different types. The array *can be pointed at*, but it doesn't mean it *is* a pointer. The `aa` variable takes ten times `sizeof(int)` bytes of memory, the `ap` variable *itself* takes the size of a pointer. The similarities do not make them the same. After all there are similarities between those two and `std::vector<int>`, but...
Michael Krelin - hacker
ralu, just thought of you commenting on some other question. Think of the difference between `int a[10][10]` and `int **`.
Michael Krelin - hacker
A: 

No.1. const char *str = "hello" ;

No.2. const char str[] = "hello" ;

No.1 answer is much better I feel as the string "hello" will be located in the text/code segment hence saving stack/data segment which is used in No.2 incase its a local variable its stored in stack else in datasegment

Use of #define will make the code segment much bigger so that is not preferable.

pdssn
Neither string will be allocated on the stack if the declarations are placed at the top level.
yes,incase its a global variable ..it wont be placed at stack
pdssn