Search code examples
c++string-literals

Why does const char[] get converted to const char* all the time?


So, I'm aware that a string literal has a type of const char[N]. And I'm also aware that if we got a const char[] parameter in some function, compiler automatically converts it to const char*.

But why do I always get compiler error messages saying that a string literal has a type of const char*?

Here's a few examples:

void f(int x) {}
int main()
{
    f("Hello");
    return 0;
}

ERROR: invalid conversion from 'const char*' to 'int'

void f() {
    throw "Hello";
}
int main()
{
    try{ f(); } catch (int x) { std::cout << "No\n";}
    return 0;
}

In terminal: terminate called after throwing an instance of 'char const*'

EDIT: I'm using GNU GCC.


Solution

  • Why does const char[] get converted to const char* all the time?

    Generally, because there is another rule closely related to the function parameter adjustment that you mentioned:

    [conv.array] Array-to-pointer conversion

    An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion ([conv.rval]) is applied. The result is a pointer to the first element of the array.

    [basic.lval] Value category

    Whenever a glvalue appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue, array-to-pointer, or function-to-pointer standard conversions are applied to convert the expression to a prvalue.

    Colloquially, this implicit conversion is called pointer decaying.

    The error message appears to describe an attempt to convert this intermediary result of lvalue-to-rvalue conversion to the parameter type.

    In terminal: terminate called after throwing an instance of 'char const*'

    In this particular case of exception throwing, there is a specific rule, which is essentially same as pointer decaying, but in context of a throw:

    [expr.throw] Throwing an exception

    Evaluating a throw-expression with an operand throws an exception; the type of the exception object is determined by removing any top-level cv-qualifiers from the static type of the operand and adjusting the type from “array of T” or function type T to “pointer to T”.

    So, the adjusted type of the exception object is in fact const char*, and it is this uncaught object that the compiler generated message describes.


    For completeness, here is the parameter adjustment rule that you knew:

    [dcl.fct] Functions

    ... After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”

    P.S. there is also an analogous adjustment rule for exception handlers:

    [except.handle] Handling an exception

    A handler of type “array of T” or function type T is adjusted to be of type “pointer to T”.