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

标签 c pointers casting struct

一边看:

Can a C compiler add padding before the first element in a structure?

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *cstr;
    size_t len;
} str_t;

void setStr(str_t* dest, const char* src)
{
    size_t len = strlen(src);
    dest->cstr = malloc(len + 1);
    dest->len = len;
    memcpy(dest->cstr, src, len + 1);
}

int main(void)
{
    str_t str;
    setStr(&str, "woot!");
    printf("%s\n", str);
    return 0;
}

令人惊讶的是,这确实有效。这个电话:

printf("%s\n", str);

似乎等同于这个:

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

所以问题是:

  1. 为什么不允许将结构转换为指针类型?
  2. 如果不允许转换,printf 怎么能正确处理这个问题?

最佳答案

Why isn't it allowed to cast a struct to a pointer type?

因为没有意义。您如何将一大堆不同类型的可能不相关的信息重新解释为简洁的内存地址?然而,在你问的上一个问题中,所有回答的人,cited the C standard ,并且标准中的一个特定声明指出

The address of the structure is the address of its first element

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

strcpy(destination, *(const char **)&str);

出于我刚才列举的原因,这“会奏效”。

How come that printf deals with this correctly if casting isn't allowed?

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

> 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

那么,现在 printf() 将要做的是:

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

此外,这仍然是未定义的行为,尽管它有效 - 如果您没有为 printf() 指定实际上对应于您作为其可变参数传入的类型,这是不一致的,您可以预期会发生任何事情。

关于将结构转换为指向其第一个元素的指针类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13210741/

相关文章:

c - 制作一个简单的计算器

c - 使用memset来防止 ''可变大小的对象可能无法初始化'

c - 检测耳机插孔插入并更改音量设置

c++ - shared_ptr的机制

c - char* 和 char** 之间的区别(在 C 中)

c++ - 从 int 转换为 struct 时出现问题

c - nedtries 的作者用 "in-place"表示什么?

不明白为什么会有这种行为

sql - SSIS 的值类型 ComObject 只能转换为 Object 类型的变量

C# 类型转换怪癖 - 接口(interface)作为泛型类型