【问题标题】:Is it safe to pass an intptr_t to a function that expects an int?将 intptr_t 传递给需要 int 的函数是否安全?
【发布时间】:2013-04-06 16:38:26
【问题描述】:

更具体地说,如果我有以下函数指针类型:

typedef void (*callback_type) (intptr_t context, void* buffer, size_t count);

我可以安全且没有“未定义的行为”吗:

callback_type func_ptr = (callback_type)write;
intptr_t context = fd;

func_ptr(context, some_buffer, buffer_size);

?

其中write() 是系统调用(编辑:具有签名ssize_t write(int fd, const void *buf, size_t count);,因此将int 作为第一个参数),fdint 文件描述符。我假设 C 和 C++ 的答案是相同的,所以我标记了两者。

【问题讨论】:

  • 你所问的似乎与标题所问的相反。编辑:啊,write 系统调用需要int
  • 好吧,context 的类型是 intptr_t,并且正在传递给 write,它需要 int。对我来说似乎是正确的......
  • 嗯?目前,您将intptr_t 传递给需要intptr_t 的函数。那么问题出在哪里?您担心的部分是什么?从&writecallback_type 的转换,从fdintptr_t 的转换还是别的什么?
  • @lvella 你没有解释writeint 作为它的第一个参数。 func_ptr 的分配是否正确编译?如果是这样,那么intptr_t 在你的机器上必须是int,不是吗?
  • @sftrabbit:分配涉及重新解释转换,因此无论转换是否有效,它都会编译。如果intptr_t 不是int,您将获得未定义的行为。

标签: c++ c callback function-pointers


【解决方案1】:

没有

这不会是可移植的,因为您传递的参数在常见的 LP64 范例中将具有不同的大小。

另外,你没有用正确的类型解引用函数指针,并且 that 的结果是未定义的。

现在,您似乎已经得出结论,函数指针将按预期工作,唯一的实际问题将是:write(2) 将如何解释 intptr_t 第一个参数?

实际的运行时问题是,在 LP64 上,您将 64 位值传递给 32 位参数。这可能会使后续参数错位。在带有寄存器参数的系统上,它可能工作得很好。

【讨论】:

    【解决方案2】:

    让我们看看 C 标准。

    C11 (n1570),第 6.3.2.3 节指针

    指向一种类型的函数的指针可以转换为指向 另一种类型的功能并再次返回;结果应比较 等于原来的指针。如果使用转换后的指针调用 类型与引用类型不兼容的函数, 行为未定义。

    C11 (n1570), § 6.7.6.3 函数声明符(包括原型)

    对于要兼容的两个函数类型,两者都应指定 compatible 返回类型。此外,参数类型列表,如果两者都存在, 参数数量和省略号的使用应一致 终结者;对应的参数应该有兼容的类型。

    C11 (n1570), § 6.2.7 兼容类型和复合类型

    如果类型相同,则两种类型具有兼容的类型。

    结论:

    void (*) (intptr_t context, void* buffer, size_t count);
    

    无法转换为:

    void (*) (int context, void* buffer, size_t count);
    

    【讨论】:

      【解决方案3】:

      问题不在于在函数之间来回传递参数,因为已经完成了从一种整数类型到另一种整数类型的自动提升。

      问题是,如果intptr_tint 短,那么不是int 的每个值都可以用intptr_t 表示?在这种情况下,int 中的一些最高位将在转换为intptr_t 时被截断,因此您最终会将write() 转换为无效的文件描述符。虽然这不应该调用未定义的行为,但它仍然是错误的。

      【讨论】:

      • intptr_t 的重点不是能够同时保存int 和指针吗?
      • @lvella 重点是它是一个整数类型,保证足够大以容纳一个指针。但是不能保证它能够容纳什么样的整数。保证只是类型本身是整数类型
      • @lvella 据我所知,intptr_t 是保证能够保存指针的整数类型,仅此而已。标准中有什么要求sizeof(T *) <= sizeof(int)
      • @H2CO3 我知道没有要求。
      • @sftrabbit 谢谢。对,那么这是一个真正的问题。
      猜你喜欢
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多