3

I've got a function which receives a char * argument:

Foo::Foo (char * arg0) {
    ....
}

In the original example, a char[] is used to pass this value...

char bar[] = "Bar";
Instance.foo (bar);

...which works fine.

But, I've found that I can pass a string literal, cast as a char *, without any warnings from the compiler.

Instance.Foo ((char *) "Bar");

However, from my reading, it seems that should be avoided - the value of the memory that is pointed to could change.

Is the above statement true ("this should be avoided") or is this appropriate in this situation?


Edit - further research turned up this article which addresses my question pretty well...

Ben
  • 54,723
  • 49
  • 178
  • 224
  • If you're 100% sure the function doesn't modify it, and you can't change the function's signature to show it, `const_cast` is an option. Otherwise, I'd stick to copying it to a new buffer. – chris Oct 31 '12 at 01:06
  • OK. So is my understanding correct, or is there a different reason? – Ben Oct 31 '12 at 01:08
  • Is there any reason you're not using `std::string`s? You won't have any of these problems. – Xymostech Oct 31 '12 at 01:08
  • The reason it works is due to legacy, but modifying the contents of a string literal is undefined behaviour, so you don't want that. I'd expect something like `warning: deprecated conversion from string literal to char *` from GCC. – chris Oct 31 '12 at 01:09
  • 2
    Best to change the function signature to accept a `char const *`. – Kerrek SB Oct 31 '12 at 01:10
  • @Xymostech - working with Win32 API, trying to stick with the program and answer my little niggles at the same time. – Ben Oct 31 '12 at 01:10
  • @Steve, It is rather annoying trying to use better types with that. `std::string` doesn't have anything for a `char *` and `std::vector` can, but doesn't include string functions. – chris Oct 31 '12 at 01:11
  • Do you know, or can you find out, why the function defines its parameter as `char * arg0` rather than `const char * arg0`? You mentioned the Win32 API; is the function part of that API? If so, which one is it? – Keith Thompson Oct 31 '12 at 01:46
  • It's the class name in WNDCLASSEX which requires a LPCTSTR. (msdn.microsoft.com/en-us/library/windows/desktop/…). I'm playing with a tutorial that has the signature rewritten slightly. – Ben Oct 31 '12 at 02:04

2 Answers2

10

Yes, avoid that. Now, if your function took a const char * there is nothing wrong with calling it with a string literal.

C++ compilers support string-literal to char * for backwards compatibility reasons only, and writing to a string literal results in undefined behavior.

When you do char bar[] = "Bar"; you are doing something fundamentally different (namely initializing an array of 4 characters with the values {'B', 'a', 'r', '\0'} that you are free to modify) than when you do char bar* = "Bar"; (where you are creating a non-const pointer to a 4 byte string that you may not modify).

In my opinion, you should never turn a string literal directly into a char*, instead put it into a const char* then (if you are communicating with a legacy API) explicitly const_cast<char*> the constness away, with a comment saying you are talking to a legacy API that has guarantees not to change the chars. The advantage of this is you can search your program for those const_casts when the API is upgraded, or you want to find where the segmentation fault involving writing to a char* came from.

One could even wrap the legacy API with const char* versions that do the const_cast within them.

The absolute worst situation would be having a bunch of char*s hanging around, some of them writable, others from string literals.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

This should be avoided at almost all cost and only be done if you have to interface with broken legacy API's and only if you have had a look at their source code and made sure they are not writing to the string.

Stay on the safe side of things and copy the string with strcpy before you pass it in.

What exactly is evil? Writing to string literals is undefined behavior.

pmr
  • 58,701
  • 10
  • 113
  • 156
  • `Writing to string literals is undefined behavior` - not sure what you mean - can you expand a bit? – Ben Oct 31 '12 at 01:14
  • @Steve, String literals are stored in read-only memory. Attempting to modify read-only memory is bad. The undefined behaviour part just means the language isn't responsible for whatever the compiler decides to do. It could format your hard drive if it wanted to. – chris Oct 31 '12 at 01:14
  • Ahhh. And another ray of light shines through the clouds. Thanks - time to go back to the books. – Ben Oct 31 '12 at 01:16
  • 3
    @Steve String literals **might** be stored in read-only memory or subject to whatever optimizations your compiler can concoct. Writing to them has undefined behavior. If you have trouble with that term I suggest reading http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior – pmr Oct 31 '12 at 01:17