Successfully writing to a string literal
-
Had to debug a crash today where the 32 bit build of an application was crashing, but the 64 bit build wasn't. There was a method that takes a string (
char *
) buffer as an in / out argument as follows.void SomeClass::someMethod(char * arg1, /* some other args */)
{
// do somethingarg1\[i\] = '\\0'; // i is a location within the buffer's size return;
}
The caller was supposed to call it with a variable, but one caller was passing a string literal, so naturally it caused an access violation.
obj.someMethod("string_literal");
However the 64 bit build was working fine. After some fiddling around, I discovered that it was due to the project's optimization settings. The assignement apparently has no effect, so the compiler was removing it in the 64 bit build. Disabling optimization caused the 64 bit build to crash too. Of course I had to come up with all kinds of crazy reasons first, thinking it was something to do with how 64 bit applications pass arguments, etc. No more in/outs.
const char *
is much safer, and will keep you sane (until you cast away theconst
, of course). -
Had to debug a crash today where the 32 bit build of an application was crashing, but the 64 bit build wasn't. There was a method that takes a string (
char *
) buffer as an in / out argument as follows.void SomeClass::someMethod(char * arg1, /* some other args */)
{
// do somethingarg1\[i\] = '\\0'; // i is a location within the buffer's size return;
}
The caller was supposed to call it with a variable, but one caller was passing a string literal, so naturally it caused an access violation.
obj.someMethod("string_literal");
However the 64 bit build was working fine. After some fiddling around, I discovered that it was due to the project's optimization settings. The assignement apparently has no effect, so the compiler was removing it in the 64 bit build. Disabling optimization caused the 64 bit build to crash too. Of course I had to come up with all kinds of crazy reasons first, thinking it was something to do with how 64 bit applications pass arguments, etc. No more in/outs.
const char *
is much safer, and will keep you sane (until you cast away theconst
, of course).The assignment arg1[i] = '\0'; wouldn't work with a const char * (at least it shouldn't). ;) Also, shouldn't a string literal be implicitely cont char * and create a compiler error when being passed to a function that expects a char * as parameter?
The good thing about pessimism is, that you are always either right or pleasently surprised.
-
Had to debug a crash today where the 32 bit build of an application was crashing, but the 64 bit build wasn't. There was a method that takes a string (
char *
) buffer as an in / out argument as follows.void SomeClass::someMethod(char * arg1, /* some other args */)
{
// do somethingarg1\[i\] = '\\0'; // i is a location within the buffer's size return;
}
The caller was supposed to call it with a variable, but one caller was passing a string literal, so naturally it caused an access violation.
obj.someMethod("string_literal");
However the 64 bit build was working fine. After some fiddling around, I discovered that it was due to the project's optimization settings. The assignement apparently has no effect, so the compiler was removing it in the 64 bit build. Disabling optimization caused the 64 bit build to crash too. Of course I had to come up with all kinds of crazy reasons first, thinking it was something to do with how 64 bit applications pass arguments, etc. No more in/outs.
const char *
is much safer, and will keep you sane (until you cast away theconst
, of course).That is really interesting and a great write-up. Very clear too. It seems crazy to me, however, that the char * is "safer / saner" because it is somewhat more dangerous. The in/out should force more control, like requiring the user to create a variable on the stack first, right? Also, you said,
Indivara wrote:
so the compiler was removing it in the 64 bit build
What do you mean "removing it"? Do you mean it actually just ignored the value sent in? That could drive you crazy, when you're trying to figure out why it isn't working.
-
That is really interesting and a great write-up. Very clear too. It seems crazy to me, however, that the char * is "safer / saner" because it is somewhat more dangerous. The in/out should force more control, like requiring the user to create a variable on the stack first, right? Also, you said,
Indivara wrote:
so the compiler was removing it in the 64 bit build
What do you mean "removing it"? Do you mean it actually just ignored the value sent in? That could drive you crazy, when you're trying to figure out why it isn't working.
I meant using
const char * arg1
would be a better choice in this case, not a generalization. The compiler was removing the last assignmentarg1[i] = '\0'
because it had no effect. The thing was thrown together in a hurry and the assignment was 'insurance' against the caller forgetting to add it. Had the reverse effect ironically. -
The assignment arg1[i] = '\0'; wouldn't work with a const char * (at least it shouldn't). ;) Also, shouldn't a string literal be implicitely cont char * and create a compiler error when being passed to a function that expects a char * as parameter?
The good thing about pessimism is, that you are always either right or pleasently surprised.
It only works the other way, you can't put a non-
const
pointer in aconst
(without casting). Ignore that, it is clearly incorrect, I'm the one who got it backwards. See below instead.const char * const_ptr;
char * non_const_ptr;// The following three are OK
const_ptr = non_const_ptr;
const_ptr = "literal";
non_const_ptr = "literal";// Causes a compiler error
non_const_ptr = const_ptr; -
I meant using
const char * arg1
would be a better choice in this case, not a generalization. The compiler was removing the last assignmentarg1[i] = '\0'
because it had no effect. The thing was thrown together in a hurry and the assignment was 'insurance' against the caller forgetting to add it. Had the reverse effect ironically.Ah, okay. I see what you mean now. Thanks for clarifying.