【问题标题】:When are values implicitly converted to pointers?何时将值隐式转换为指针?
【发布时间】:2023-11-10 13:20:01
【问题描述】:

我有很多功能,例如:

void write(char* param, int len)
{
    //
}

我注意到我几乎从不使用& 运算符作为参数。当我传递一个数组时:

char in[20];
write(in, 20);

我不需要它,但是当我传递一个值时:

write(5, 1);

我似乎不需要它,当我传递一个指针时:

char* in = malloc(20);
write(in, 20);

我也不需要。那么在什么情况下我实际需要调用:

write(&in, 1);

因为我很困惑:D

【问题讨论】:

    标签: c arguments c99 argument-passing


    【解决方案1】:

    你确定你的第二个案例吗?它不适合我,应该是

    char in = 5;
    write(&in, 1);
    

    【讨论】:

    • 我正在使用 GCC,它编译时没有警告我?但我使用的是 write(5, 1),而不是像示例中那样使用中间变量。所以也许它编译是因为它认为 5 是一个指针?
    • x86 上的 GCC v4.6.2 为我提供了“来自没有强制转换的整数的指针”警告。您的问题和评论中的代码会发生这种情况。您可以尝试启用警告 - 将 -Wall 添加到您的编译器命令中 - 看看这是否有助于您查看警告。
    • 我已经启用了 -Wall。唯一的区别是它不是针对 x86 而是针对 ARM。
    • 我找到了原因。我正在调用 write(0, 1)。当我将其更改为 write(5, 1) 时,我收到警告。我认为它威胁 0 作为 NULL 指针。
    【解决方案2】:

    值何时隐式转换为指针?

    实际上,整数类型可以由编译器隐式转换为指针。理论上这是非法的,接受它的编译器通常会发出警告:

    example.c:2:6: warning: incompatible integer to pointer conversion initializing
                   'void *' with an expression of type 'int'
    

    在你上面的例子中:

    char in = 5;
    write(in, 20);
    

    char 是一个整数类型,所以如果你的编译器允许它,它可能被隐式转换为指针类型,尽管它不是 C 标准的一部分并且完全是编译器特定的.

    请注意,标准允许使用强制类型转换将整数类型转换为指针类型,尽管结果是实现定义的:

    char in = 5;
    write((char *)in, 20);
    

    隐式转换唯一允许的情况是整数常量0,它表示一个空指针:

    write(0, 20);    // allowed
    

    请注意,整数常量本身是允许的,但值为0 的整数类型的变量则不允许:

    char in = 0;
    write(in, 20);   // not allowed
    

    至于其他,当你传递一个指针时,你显然不需要&,因为它已经是一个指针。 When you pass an array, it decays to a pointer 所以你也不需要&。在这两种情况下,使用它实际上是非法的,因为您上面的函数需要 char * 并分别得到 char **char (*)[20]

    【讨论】:

    • ... 除非标准要求:保证在 0 和任何指针类型的空指针之间进行转换,然后再返回。
    【解决方案3】:

    如果您以某种方式将函数“write”的原型复制到调用此函数的文件中,如下所示。

    void write(char *in, int len);
    
    void foo(int bar){
       char in=5;
       write(in, 1);
    }
    

    您可能会收到警告。因为 in 不是指针,虽然 5 可以是地址。 我猜如果你的程序编译链接成功,它会在运行时崩溃。

    【讨论】:

      【解决方案4】:

      使用; return_type function_name(prim_data_type* param...) param 是指向内存中地址的指针,*param 是该地址中的值。 答案是关于你想用这个param做什么。

      char in[20];
      

      通过说“in”是第一个元素的地址。所以在函数调用处:

      write(in, 20);
      

      您正在发送第一个元素的地址,因此在函数实现中,您可以通过*param 访问第一个元素,通过*(param+1)param[1] 等访问第二个元素。 你困惑的地方在这里:

      char in = 5;
      write(in, 1);
      

      因为 in 是地址 5 (00000005),所以在函数的实现中,您正在访问该位置的任何值。你必须小心这样使用。

      在malloc操作中:

      char* in = malloc(20);
      write(in, 20);
      

      in 是一个指向地址(第一个元素的地址)的指针,它容纳 20 个 char 元素可以占用空间。在函数中,您可以使用参数指针访问所有元素(*param 是第一个元素,*(param+7)param[7] 是第8个元素)

      总之,当你想在另一个函数中使用主要数据类型变量(int、float、char..)时,你必须使用;

      write(&in);
      

      通过这样做,在该 write 函数的实现中,您可以访问该变量,将值更改为 *param 而不会造成混淆。

      注意:为了更好地理解,这里简化了一些解释。在这里欢迎额外的警告。

      【讨论】:

        【解决方案5】:

        在某些情况下,函数和数组会衰减为指针。函数可以衰减为指向函数的指针,数组可以衰减为指向数组第一个元素的指针。没有其他类型有这种行为。

        这个例子:

        char in = 5; 
        write(in, 1);
        

        虽然错了。在这种情况下,您肯定需要&。你确定它是这样工作的吗?

        【讨论】:

        • 这也可能是错误的。并且不应该在没有警告的情况下编译。从整数到指针类型的对话需要显式转换。
        • 我没有收到来自 GCC 的任何警告
        • 正如你在其他 cmets 中提到的,你是。您应该确保在这里准确地告诉我们您在做什么,而不是几乎您在做什么。