Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is passing a string literal into a char* argument only sometimes a compiler error?

I'm working in a C, and C++ program. We used to be compiling without the make-strings-writable option. But that was getting a bunch of warnings, so I turned it off.

Then I got a whole bunch of errors of the form "Cannot convert const char* to char* in argmuent 3 of function foo". So, I went through and made a whole lot of changes to fix those.

However, today, the program CRASHED because the literal "" was getting passed into a function that was expecting a char*, and was setting the 0th character to 0. It wasn't doing anything bad, just trying to edit a constant, and crashing.

My question is, why wasn't that a compiler error?

In case it matters, this was on a mac compiled with gcc-4.0.

EDIT: added code:

char * host = FindArgDefault("EMailLinkHost", "");
stripCRLF(linkHost, '\n');

where:

char *FindArgDefault(char *argName, char *defVal) 
{// simplified
    char * val = defVal;
    return(val);
}

and

void stripCRLF(char *str, char delim)
{
    char *p, *q;

    for (p = q = str; *p; ++p) {
        if (*p == 0xd || *p == 0xa) {
            if (p[1] == (*p ^ 7)) ++p;
            if (delim == -1) *p = delim;
            }
        *q++ = *p;
        }
    *q = 0;  // DIES HERE
}

This compiled and ran until it tried to set *q to 0...

EDIT 2:

Most people seem to be missing the point of my question. I know why char foo[] = "bar" works. I know why char * foo = "bar"; doesn't work.

My question is mostly with respect to passing parameters. One thing that occures to me is "Is it possible that this is a C vs C++ issue?" because I have some .c files and some .cpp files, and it's quite possible that C allows it, but C++ doesn't... or vice versa...

like image 888
Brian Postow Avatar asked May 03 '10 19:05

Brian Postow


2 Answers

The standard specifies a special rule allowing the literal-to-char* conversion which quietly drops const qualification. (4.2/2):

A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]

The C++0x standard takes that deprecation further… this nonsense rule is removed entirely from the upcoming standard.

The const char* to char* error must be a result of converting a literal to a const char* first.

like image 127
Potatoswatter Avatar answered Sep 22 '22 19:09

Potatoswatter


Using a string literal to initialize a char * pointer in C++ is a deprecated feature, but nevertheless it is legal. It is not an error. It is your responsibility to make sure that no modification attempts are made through such a pointer.

In other words, you must be misunderstanding something about the compilation errors you got earlier. I don't think you ever got any errors for such an initialization/assignment. The "Cannot convert const char* to char*" errors you mention in your question must have been produced by something else.

Note, that the fact that you can initialize char * pointer with a string literal does not mean that you can use any arbitrary const char * value to initialize a char * pointer. This code

const char *pc = "A";
char *p = pc;

will produce an error, while this

char *p = "A";

will not. The aforementioned deprecated feature applies to string literals only, not for all const char * pointers.

like image 22
AnT Avatar answered Sep 21 '22 19:09

AnT