在C中,以下是嗅探器代码,
void Handle_IP(char *buf)
{
struct iphdr *ip_hdr; // declaring pointer of type ip header
struct in_addr in; // declaring a structure which holds ip address
FILE *fp;
int ctl, len;
/* In the following statement we're adjusting the offset so that
ip pointer can point to correct location */
ip_hdr = (struct iphdr *)(buf + 14);
....
}
行,
ip_hdr = (struct iphdr *)(buf + 14)
的{{1}}类型已投放到char *
。
GO是一种类型安全的语言,不允许这种类型的转换。除了结构类型
之后的struct iphdr *
,Go没有void *
如何在GO中处理此类代码?
答案 0 :(得分:6)
让我们从不同的角度来看待这个问题:类型转换在C中做了什么?
嗯,从某种意义上说,它没有做任何事情!它只需要在内存中的某个点上采用一些位模式,并盲目地假设这个特定的位模式实际上代表了某种类型的值。但是没有对此进行验证,没有任何解析。这就是问题所在。
但是,我已经使用了上述问题的解决方案:解析。而不是盲目地假设内存中的某些随机位模式是C编译器为某种类型的值生成的相同位模式,我们实际上查看位模式,检查它是否符合如何构造该数据类型的位模式的规则,并根据这些规则将位模式解构为其组成部分。
换句话说:我们写一个解析器。
请注意,这不是Go特有的。即使在C中也是一个好主意。实际上,您发布的代码至少有三种,也许是四种不同的方式:
char
不是8位宽的平台AFAIK,已有现有的IP,UDP和TCP解析器写在Go那里,你可以使用或学习。此外,来自Alan Kay的Viewpoints Research Institute的当前系统有一个非常酷的TCP / IP堆栈,只需120行左右,非常容易阅读。 (事实上,解析器的源代码实际上只包含从RFC中剪切和粘贴的ASCII图。)
答案 1 :(得分:3)
前言:尽管您想要的是可能的,但请尽量避免使用包unsafe
。这不是"转到第一个"解决方案,而是将其视为最后的手段(或之后的事情)。
Go会在unsafe
包中为您提供支持。
即使是规范也有专门的部分。 Spec: Package unsafe
:
编译器已知的内置包
unsafe
为低级编程提供了工具,包括违反类型系统的操作。使用unsafe
的包必须手动审查以确保类型安全,并且可能无法移植。
该软件包被故意命名为unsafe
,为您提供正确的事先警告,如果出现问题,请不要责怪编译器或语言。
您需要的是unsafe.Pointer
类型。 Pointer
是一个特殊的pointer type,可能不是dereferenced,但任何指针类型都可以转换为Pointer
,Pointer
可以转换为任何({1}} )指针类型。所以这是你的网关"不同类型之间。
例如,如果您的值为float64
(内存中为8个字节),则可以将这8个字节解释为int64
(内存中也是8个字节),如这样:
var f float64 = 1
var i int64
ip := (*int64)(unsafe.Pointer(&f))
i = *ip
fmt.Println(i)
输出(在Go Playground上尝试):
4607182418800017408
关键是这一行:
(*int64)(unsafe.Pointer(&f))
表示取f
的地址(类型为*float64
),将其转换为unsafe.Pointer
(任何指针类型都可以转换为Pointer
),然后将此unsafe.Pointer
值转换为另一个指针类型*int64
。如果我们取消引用此指针,则会得到类型int64
的值。
在您的示例中,您希望"放置"应用了偏移量的地址上的变量。 Go没有指针算术。你可以通过两种方式解决这个问题:
使用可能包含地址的uintptr
,但您可以将其视为int
并为其添加值
或使用指向&#34;缓冲区的指针&#34;类型,例如*[1<<31]byte
;您可以将地址转换为此指针,并且可以通过在给定偏移处索引缓冲区来应用偏移量,并获取该元素的地址,例如&buf[14]
方法#1看起来像这样:
type X [16]byte
var x = X{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
xx := (uintptr)(unsafe.Pointer(&x[0])) + 14 // APPLY OFFSET
var x2 X = *(*X)(unsafe.Pointer(xx))
fmt.Println(x2[0], x2[1])
输出(在Go Playground上尝试):
14 15
方法#2可能如下所示:
type X [16]byte
var x = X{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
xx := (*X)(unsafe.Pointer(&x[0]))
xx = (*X)(unsafe.Pointer(&xx[14])) // APPLY OFFSET
var x2 X = *(*X)(unsafe.Pointer(xx))
fmt.Println(x2[0], x2[1])
输出是一样的。在Go Playground上尝试。