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
可以正确处理这个问题strcpy(destination, *(const char **)&str);
而这“将起作用”的原因正是我刚才列举的
如果不允许铸造,printf怎么能正确处理这个问题
因为在C中,类型转换通常只是为了愚弄编译器(除非不是这样)。通过传递结构,结构将被复制,堆栈将类似于(为了简单起见,我有意省略结构中的任何填充):
因此,现在printf()
将要做的是:
- 从堆栈中弹出第一个值。它将是格式字符串
- 现在,当它在格式字符串中遇到
格式说明符时,它将弹出另一个字符指针-实际上,它是指向结构的指针,也是指向第一个元素的指针,即要打印的字符串%s
- 因此,它愉快地打印字符串并返回
此外,这仍然是未定义的行为,尽管它可以工作-如果不为
printf()
指定一个格式字符串,该字符串实际上对应于作为其可变参数传入的类型,那么这是不一致的,并且您可以期待任何事情发生。这不起作用,因为str.cstr!=&str
。。。。但这太难看了-(shiverstr.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