C++ char*[] to char** conversion

后端 未结 3 2022
鱼传尺愫
鱼传尺愫 2021-02-19 01:00

I have this simple code that compiles without errors/warnings:

void f(int&, char**&){}

int main(int argc, char* argv[])
{
    f(argc, argv);
    return          


        
相关标签:
3条回答
  • 2021-02-19 01:22

    The type of temp in

    char* temp[] = { "", "", nullptr };

    is not char*[], it's

    char*[3]

    The latter can't be implicitly converted to `char**'.

    In main, the type of argv is an unbound char* array which is equivalent to char**

    I admit, it's confusing :)

    0 讨论(0)
  • 2021-02-19 01:27

    Jefffrey's comment references the standard, here it is:

    4.2 Array-to-pointer conversion [conv.array]

    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 result is a pointer to the first element of the array.

    And a prvalue is:

    A prvalue ("pure" rvalue) is an expression that identifies a temporary object (or a subobject thereof) or is a value not associated with any object.

    You cannot bind a non-const reference to a temporary.

    int& i = int(); // error
    
    char* argv[] = { "", "", nullptr };
    // the result of the conversion is a prvalue
    char**& test = argv; // error
    

    Therefore the following code will happily compile:

    #include <iostream>
    
    void f(int& argc, char** const& argv){
        std::cout << argv[0] << std::endl; // a
    }
    
    int main()
    {
        int argc = 2;
        char* argv[] = { "a", "b", nullptr };
        f(argc, argv); 
        return 0;
    }
    

    One important thing I glazed over is pointed out in Kanze's comment.

    In the first example provided in the OP, char* argv[] and char** argv are equivalent. Therefore, there is no conversion.

    std::cout << std::is_array<decltype(argv)>::value << std::endl; // false
    std::cout << std::is_array<char**>::value << std::endl; // false
    std::cout << std::is_array<char*[]>::value << std::endl; // true
    std::cout << std::is_same<decltype(argv), char**>::value << std::endl; // true
    std::cout << std::is_same<decltype(argv), char*[]>::value << std::endl; // false
    
    0 讨论(0)
  • 2021-02-19 01:42

    Because despite appearances, the second argument to main has type char**. When used as the declaration of a function argument, a top level array is rewritten to a pointer, so char *[] is, in fact, char**. This only applies to function parameters, however.

    A char*[] (as in your second case) can convert to a char**, but the results of the conversion (as with any conversion) is an rvalue, and cannot be used to initialize a non-const reference. Why do you want the reference? If it is to modify the pointer, modifying the char** argument to main is undefined behavior (formally, in C, at least—I've not checked if C++ is more liberal here). And of course, there's no way you can possibly modify the constant address of an array. And if you don't want to modify it, why use a reference?

    0 讨论(0)
提交回复
热议问题