4

Possible Duplicate:
Are string literals const?

Is the following valid in ANSI C?

#include <stdio.h>

/* This returns "Hans" if arg != 0, "Gretel" if arg == 0 */
char* foo(int arg)
{
    return arg ? "Hans" : "Gretel";
}

int main()
{
    char* p_ch;

    p_ch = foo(1);
    printf("%s\n", p_ch);
    p_ch = foo(0);
    printf("%s\n", p_ch);

    return 0;
}

The code compiles and runs well under GCC/Linux.

MinGW/Windows says:

invalid conversion from `const char*' to `char*'

MS Visual C/C++ 2008 is fine with the code.

  1. Can I assign a char* variable to a literal string elsewhere than at the point of its initialization?
  2. I've read that string literals have static alocation class. Does it mean that they are invisible outside of the function which they were defined in?
  3. Since when are conversions from const types to their non-const counterparts invalid?
Community
  • 1
  • 1
peter.slizik
  • 2,015
  • 1
  • 17
  • 29
  • I would declare `foo` as returning `const char*`. And when compiled as C++, the code becomes invalid. I'm not enough a standard expert to explain why precisely... I would have expected GCC to give some warning (but even gcc 4.6 with `-Wall -Wextra` don't). – Basile Starynkevitch Nov 23 '11 at 15:29
  • @Basile, because gcc is compiling C code. There is _nothing_ wrong with this in C. If you were to compile it with g++, that would be another matter but obviously gcc doesn't consider it a problem if you try to compile perfectly valid C code. A warning like "Cannot use variable name of `new` on the off chance you may want to one day compile this with a C++ compiler" would be damnably annoying :-) – paxdiablo Nov 23 '11 at 15:33
  • 1
    @BasileStarynkevitch: `gcc -Wwrite-strings` gives an appropriate warning. This is probably not part of `-Wextra` because some parts of the C library may depend on this feature; e.g., `strerror` has return type `char*` but may be implemented using an array of string literals. – Fred Foo Nov 23 '11 at 15:36
  • Thanks for all the answers. Anyway, since string literals belong to the `static` allocation class, shouldn't they be technically invisible from outside of the function foo()? Yes, I know, a static variable is only a disguised global, and as such they live until the program is terminated, and in turn `p_ch` remains a valid pointer - but can I rely on this behavior? – peter.slizik Nov 23 '11 at 15:43

2 Answers2

6

Yes, this is valid standard C. However, it's only valid because string literals have type char[] for backwards compatibility; you should really make the return value from foo a const char* for safety. Writing to either of the strings returned by foo provokes undefined behavior.

If your compiler complains about this, then you may have accidentally used a C++ compiler. In C++, strings literals have type const char []. (If you change char* to const char*, your program magically becomes a valid C++ program as well.)

Can I assign a char* variable to a literal string elsewhere than at the point of its initialization?

You mean

char *p;
// do some other stuff
p = "literal";

? Yes, that's possible.

I've read that string literals have static allocation class. Does it mean that they are invisible outside of the function which they were defined in?

You're confusing static allocation and static variables. You can certainly use the result from foo in another translation unit.

Since when are conversions from const types to their non-const counterparts invalid?

Officially since 1989, when const was introduced to C. You have to explicitly cast the const off.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
1

The error message you are getting from MinGW/Windows compiler strongly suggests that you are compiling this code as C++. In C language string literals have char[N] type (as opposed to const char[N] in C++). In C language you should not get this error message. Nevertheless, even in C string literals are non-modifiable, meaning that it is a good idea to stick to const char * pointers when pointing to string literals.

Your question number 1 is a bit weird. String literals are nameless objects, which means that initialization is the only way to directly make a pointer to point to a string literal. There's no other way. Later you can copy your non-const pointer to other non-const pointers, which is OK. Just remember that you are not allowed to write anything into a string literal through those pointers: string literals are non-modifiable.

Your question 2 also makes little sense. "Visibility" is a property of a name. String literals are nameless objects. They are not visible anywhere. They can't be visible, since they have no names. Since they have no names, the only way to "grab" a string literal and hold on to it is to attach a pointer to it during pointer initialization (as in your examples). Visibility has nothing to do with it at all. String literals do indeed have static storage duration, which means that they "live forever": they exist as long as the program runs. In your example, string literals "Hans" and "Gretel" continue to live even after the foo exits, meaning that the pointer returned by foo remains valid.

The answer to your question 3 is: implicit conversions from const pointers to their non-const counterparts never existed in C language, i.e. it has always been invalid. You have to use an explicit cast in order to perform such a conversion.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765