将intptr_t传递给期望int的函数是否安全?

时间:2013-04-06 16:38:27

标签: c++ c callback function-pointers

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

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作为第一个参数),fd是{{1}文件描述符。我假设C和C ++的答案是相同的,所以我正在标记两者。

3 个答案:

答案 0 :(得分:6)

这将不可移植,因为您传递的参数在公共LP64范例中将是不同的大小。

此外,您没有取消引用具有正确类型的函数指针,并且 的结果未定义。

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

实际的运行时问题是,在LP64上,您将64位值传递给32位参数。这可能会使后续参数不对齐。在具有寄存器参数的系统上,它可能会正常工作。

答案 1 :(得分:2)

让我们来看看C标准。

  

C11(n1570),§6.3.2.3指针

     

指向一种类型的函数的指针可以转换为指向a的指针   另一种类型的功能又回来了;结果应该比较   等于原始指针。如果转换的指针用于调用   一个类型与引用类型不兼容的函数,   行为未定义。

     

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

     

要兼容两种功能类型,两者都应指定兼容   返回类型。此外,参数类型列表,如果两者都存在,   应同意参数的数量和省略号的使用   终止;相应的参数应具有兼容的类型。

     

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

     

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

结论:

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

无法转换为:

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

答案 2 :(得分:1)

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

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