C 将结构强制转换为指向其第一个元素的指针类型

C 将结构强制转换为指向其第一个元素的指针类型,c,pointers,casting,struct,C,Pointers,Casting,Struct,在看: 我想出了以下代码: (忽略本例中未释放内存的事实。) 似乎相当于这个: printf("%s\n", str.cstr); 因此,人们可能会认为以下情况也是可能的: char* plainstr = malloc(str.len + 1); strcpy(plainstr, str); 但是不行。与printf相反,strcpy不是可变的,因此存在类型检查。编译器有理由抱怨: passing 'str_t' to parameter of incompatible type 'co

在看:

我想出了以下代码:
(忽略本例中未释放内存的事实。)

似乎相当于这个:

printf("%s\n", str.cstr);
因此,人们可能会认为以下情况也是可能的:

char* plainstr = malloc(str.len + 1);
strcpy(plainstr, str);
但是不行。与
printf
相反,
strcpy
不是可变的,因此存在类型检查。编译器有理由抱怨:

passing 'str_t' to parameter of incompatible type 'const char *'
但是试图通过强制转换来告诉编译器“我是认真的”:

strcpy(plainstr, (const char*)str);
也不行:

operand of type 'str_t' where arithmetic or pointer type is required
请注意,以下操作无法工作:

strcpy(plainstr, (const char*)&str);
str.cstr!=&str
。例如,此文件的输出:

printf("%p %p\n", str.cstr, &str);
详情如下:

0xbdb010 0x7fff788f6ab8
事实上,垃圾数据正被复制到
plainstr

因此,问题是:

  • 为什么不允许将结构强制转换为指针类型
  • 如果不允许施放,为什么
    printf
    可以正确处理这个问题
  • 为什么不允许将结构强制转换为指针类型

    因为这毫无意义。如何将一大堆不同类型的可能不相关的信息重新解释为一个简洁的内存地址?然而,在您提出的前一个问题中,所有回答的人以及标准中的一个特定声明都表示

    结构的地址是其第一个元素的地址

    所以(正如@Mat已经指出的那样),你确实可以写

    strcpy(destination, *(const char **)&str);
    
    而这“将起作用”的原因正是我刚才列举的

    如果不允许铸造,printf怎么能正确处理这个问题

    因为在C中,类型转换通常只是为了愚弄编译器(除非不是这样)。通过传递结构,结构将被复制,堆栈将类似于(为了简单起见,我有意省略结构中的任何填充):

    因此,现在
    printf()
    将要做的是:

    • 从堆栈中弹出第一个值。它将是格式字符串
    • 现在,当它在格式字符串中遇到
      %s
      格式说明符时,它将弹出另一个字符指针-实际上,它是指向结构的指针,也是指向第一个元素的指针,即要打印的字符串
    • 因此,它愉快地打印字符串并返回

    此外,这仍然是未定义的行为,尽管它可以工作-如果不为
    printf()
    指定一个格式字符串,该字符串实际上对应于作为其可变参数传入的类型,那么这是不一致的,并且您可以期待任何事情发生。

    这不起作用,因为
    str.cstr!=&str
    。。。。但这太难看了-(shiver
    str.cstr
    &str
    是不相等的。当然可以编译代码,但是生成的指针没有指向字符串,因此复制了错误的数据。我用显示这一点的代码更新了问题。
    str.cstr
    是保存堆上字符串地址的指针值。
    &str
    I它是堆栈上的
    结构的地址,但它也是指针值
    cstr
    的地址,该指针值保存着堆上的地址。试着比较
    &str.cstr
    &str
    @Geoff_monte称我为受虐狂,但这是我喜欢C;-)
    strcpy(destination,(const char*)&str)的原因之一不起作用。我所说的“工作”是指将
    str.cstr
    复制到
    目的地。不过,您对printf的
    printf
    如何以正确地址结尾的解释是有道理的。@NikosC。谢谢我还更新了答案-我认为它现在应该是这样工作的。由于结构的第一个元素的地址必须与结构的地址相同,我可以假设
    *(const char**)&str
    不是UB,对吗?看起来Mat的答案被删除了,但我喜欢C99标准中的引用。太糟糕了。@Geoff_Montee Mat自己把它拿走了。但这里是我引用的部分的链接。
    0xbdb010 0x7fff788f6ab8
    
    strcpy(destination, *(const char **)&str);
    
    > top of the stack: pointer to the format string
    > address of the copied struct *and*  address of the copy of the char pointer
    > address of the length of the string (size_t)
    > every other stuff