将整数值转换为 void* 是回调中常用的范例吗?
该值被转换为指针,而不是发送指向值的实际指针。我在 GTK 程序的 GUI 界面代码中找到了这些示例。
g_signal_connect (pastebutton[pane],
"clicked",
G_CALLBACK(on_paste_button_pressed),
(void*)((long)pane<<4));
在上面的示例中,我指的是 g_signal_connect 的最后一个参数。当 GTK2 调用 on_paste_button_pressed
时,on_paste_button_pressed
将 user_data
void 指针强制转换回来,如下所示:
int pane = ((long)user_data) >> 4;
实际上,我将这个特定示例添加到代码中,但是我基于已有的内容。我添加了位移以避免有关转换的警告。该程序本身有四个窗格,其中包含相当多的小部件,复制和粘贴按钮允许您将所有值从一个窗格复制到另一个窗格。
这种将值转换为指针地址的方法是否经常使用,是否有理由不使用这种方法?
编辑:
从整数到 void 指针的转换也可以这样实现:
void* void_ptr = some_int - NULL;
Rather than sending an actual pointer to a value, the value is cast to a pointer. I found these examples in the GUI interface code of a GTK program.
g_signal_connect (pastebutton[pane],
"clicked",
G_CALLBACK(on_paste_button_pressed),
(void*)((long)pane<<4));
In the above example, I am referring to the last parameter of g_signal_connect
. When on_paste_button_pressed
is called by GTK2, on_paste_button_pressed
casts the user_data
void pointer back like so:
int pane = ((long)user_data) >> 4;
Actually, I added this particular example to the code, but I based it upon what was already there. I added the bit-shifting so as to avoid warnings about casting. The program itself has four panes containing quite a number of widgets, the copy and paste buttons allow you to copy all the values from one pane to another.
Is this way of casting a value to a pointer address often used, and are there reasons why this should not be used?
edit:
The cast from an integer to a void pointer can also be achieved like so:
void* void_ptr = some_int - NULL;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
它已被使用。当它执行所需操作时,它的使用非常普遍。
不使用它的原因之一是理论上指针大小可能小于源整数大小。
不使用它的另一个原因是它允许您仅将一段整数数据传递给回调。如果将来您需要添加另一条数据(或切换到非整数),则必须找到并重写回调访问传递数据的每个位置。因此,如果您将来有可能必须扩展数据,最好创建一个
struct
(即使它只保存一个int
这次)并传递一个指向该struct
的指针。但是,如果您确定您永远不需要传递除该单个整数之外的任何内容,并且您的整数适合
void *
,那么该技术无论如何都不会被破坏。PS 迂腐地说,C 和 C++ 似乎都没有整数到 void * 到整数转换的往返保证,即它们不保证它能够工作并恢复原始整数值。
It is used. It is used quite commonly when it does what's required.
One reason not to use it is that theoretically pointer size might be smaller than the source integer size.
Another reason not to use it is that it allows you to pass only one piece of integer data to the callback. If in the future you'll need to add another piece of data (or switch to a non-integer), you'll have to locate and rewrite every single place where the callback makes access to the passed data. So, if there's a chance that you'd have to extend the data in the future, it is better to create a
struct
(even if it holds just a singleint
at this time) and pass a pointer to thatstruct
.But if you are sure that you'll never have to pass anything other than that single integer and that your integer fits into a
void *
, then this technique is not in any way broken.P.S. Pedantically speaking, neither C nor C++ appear to have the roundtrip guarantee for integer-to-void *-to-integer conversion, i.e. they don't guarantee that it will work and restore the original integral value.
您应该使用宏 GINT_TO_POINTER() 和 GPOINTER_TO_INT() 在指针和整数之间进行转换。
glib:类型转换宏
You should use macros GINT_TO_POINTER() and GPOINTER_TO_INT() to cast between pointers and integers.
glib: Type Conversion Macros
将整数转换为指针用于按值传递值。如果您确实需要按引用参数,则这是首选方法,因为编译器不需要取消引用指针。
位移位是一个坏主意,因为它可能导致溢出。
对于真正可移植的代码,您应该使用 intptr_t 作为整数类型,因为它非常适合指针。
Casting an integer to a pointer is used to pass a value by-value. This is the preferred way if you do need a by-reference parameter because the compiler then does not need to dereference the pointer.
The bit-shifting is a bad idea because it can cause overflows.
For really portable code, you should use intptr_t as your integer type cause it will nicely fit into a pointer.
是的,它确实可以在这些情况下使用。它适用于许多平台,但可能会失败,因为任意整数并不总是有效的指针值,尽管您所做的移位应该绕过这个问题。指针也可能无法容纳整数可以容纳的所有值;如果您在指针为 32 位的平台上使用 64 位
long
,就会出现这种情况,当然,由于您要移动该值,因此即使指针和整数也可能会失败大小相同。如果您想使用此技巧,您可能应该检查sizeof (void*)
与您使用的整数类型的大小,并在运行时检查实际值(如果指针不够大) 。使这个完全可移植可能不值得,这样您就可以在需要的平台上使用实际的指针,因此要么将自己限制在可以使用此技巧的平台上,要么完全放弃该技巧。It does see use in these kinds of cases, yes. It works on many platforms, but might fail because an arbitrary integer is not always a valid pointer value, though the shifting you do should get around that. It is also possible that a pointer cannot hold all the values that an integer can; this would be the case if you're using a 64-bit
long
on a platform where pointers are 32 bits, and of course since you are shifting the value, it could also fail even if pointers and integers are the same size. If you want to use this trick, you should probably checksizeof (void*)
against the size of the integer type you use, and at runtime check against the actual value if the pointer isn't big enough. It's probably not worth it to make this fully portable so that you would use an actual pointer on platforms where that's needed, so either limit yourself to platforms where this trick works or abandon the trick altogether.我觉得很好。没有关于使用频率的统计数据,但你真的关心吗?
不过,我不确定我是否理解位移位有何帮助。
I find it just fine. Don't have statistics about use frequency, but do you really care?
I'm not sure I understand how bit-shifting helps, though.
它被使用,但它绝不是便携式的,所以你必须小心。
C 标准并不强制要求指针类型至少具有与整数类型一样多的位,因此您可能并不总是能够做到这一点。
但我不记得任何平台上的指针实际上都小于整数,因此您可能是安全的(尽管在技术上并不安全)。
我认为铸造可能存在的唯一原因是消除对齐警告的可能性。 C1x 草案第 6.3.2.3 节规定:
It is used but it's by no means portable so you have to be careful.
The C standard does not mandate that pointer types have at least as many bits as integer types, so you may not always be able to do it.
But I can't recall any platform in which pointers have actually been smaller than integers so you're probably safe (despite not being technically safe).
The only reason I can think that the casting may be there for is to remove the possibility of alignment warnings. Section 6.3.2.3 of the C1x draft states:
这是来自 C-FAQ:
问:整数如何与指针相互转换?我可以暂时将整数填充到指针中,反之亦然吗?
答:从前,可以保证指针可以转换为整数(尽管人们永远不知道是否可以将 int 或 long 转换为整数)。需要),并且整数可以转换为指针,并且当转换为(足够大的)整数并再次转换回来时,指针保持不变,并且转换(以及任何映射)旨在“毫不奇怪”换句话说,整数/指针转换有一些先例和支持,但它们始终依赖于机器,因此不可移植。显式转换始终是必需的(尽管早期的编译器很少抱怨如果您忽略它们)。
ANSI/ISO C 标准为了确保 C 的广泛可实现性,削弱了那些早期的保证。指针到整数和整数到指针的转换是实现定义的(参见问题 11.33),并且不再保证指针可以在不改变的情况下转换为整数并返回。
将指针强制转换为整数,或将整数强制转换为指针,从来都不是好的做法。当您需要一个可以容纳任一类型数据的通用槽时,联合是一个更好的主意。
另请参阅问题 4.15、5.18 和 19.25。
参考文献:K&R1 Sec。 A14.4 页。 210
K&R2 段A6.6 页。 199
ISO 秒。 6.3.4
基本原理第二节3.3.4
H&S Sec. 6.2.3 页。 170,秒。 6.2.7 第 171-2 页
This is from the C-FAQ:
Q: How are integers converted to and from pointers? Can I temporarily stuff an integer into a pointer, or vice versa?
A: Once upon a time, it was guaranteed that a pointer could be converted to an integer (though one never knew whether an int or a long might be required), and that an integer could be converted to a pointer, and that a pointer remained unchanged when converted to a (large enough) integer and back again, and that the conversions (and any mapping) were intended to be ``unsurprising to those who know the addressing structure of the machine.'' In other words, there is some precedent and support for integer/pointer conversions, but they have always been machine dependent, and hence nonportable. Explicit casts have always been required (though early compilers rarely complained if you left them out).
The ANSI/ISO C Standard, in order to ensure that C is widely implementable, has weakened those earlier guarantees. Pointer-to-integer and integer-to-pointer conversions are implementation-defined (see question 11.33), and there is no longer any guarantee that pointers can be converted to integers and back, without change.
Forcing pointers into integers, or integers into pointers, has never been good practice. When you need a generic slot that can hold either kind of data, a union is a much better idea.
See also questions 4.15, 5.18, and 19.25.
References: K&R1 Sec. A14.4 p. 210
K&R2 Sec. A6.6 p. 199
ISO Sec. 6.3.4
Rationale Sec. 3.3.4
H&S Sec. 6.2.3 p. 170, Sec. 6.2.7 pp. 171-2