2013-11-01 22 views
5

Tôi đang cố gắng kết nối với một dll Windows bằng Go. Hàm dll mà tôi muốn sử dụng chấp nhận một con trỏ tới một mảng byte. Vì vậy, tôi cần phải cung cấp cho nó mảng byte đó.Golang: mảng byte động không an toàn

Tôi đang sử dụng thư viện syscall để gọi dll, như được minh họa here. yêu cầu cơ bản của tôi là:

  • tôi đưa ra kích thước cần thiết cho các mảng byte
  • tôi tạo ra các mảng byte
  • tôi phải có được một con trỏ đến mảng byte
  • tôi sau đó vượt qua con trỏ đến Windows dll

Tôi không thể hình dung cách tạo mảng byte khi di chuyển và nhận con trỏ đến đó. Điều này rõ ràng là một hoạt động không an toàn, và thư viện unsafe sẽ giúp tôi, nhưng tôi cần để có thể tạo ra một mảng byte chiều dài động ở nơi đầu tiên. Tạo một slice với "make" không giúp tôi, trừ khi tôi có thể lấy một con trỏ tới mảng sao lưu của slice.

Có ai khác đã gặp phải điều này hoặc có bất kỳ ý tưởng nào không?

Trả lời

3

Tôi nghĩ việc triển khai syscall.ComputerName https://golang.org/src/syscall/syscall_windows.go#395 sẽ là một ví dụ tốt. Nó sử dụng uint16, không phải byte, nhưng nếu không ...

Trong trường hợp của bạn, nó sẽ là ptr := &myslice[0].

Alex

+1

Rực rỡ, nó hoạt động như một sự quyến rũ. 'ptr: = & myslice [0]' – chowey

3

Tôi đã tìm thấy một giải pháp tổng thể. Rõ ràng là structure of a slice chứa một con trỏ tới mảng byte sao lưu, chiều dài của mảng byte sao lưu, và sau đó là dung lượng của mảng byte sao lưu.

Tôi chỉ quan tâm đến một con trỏ tới mảng byte, vì vậy tôi chỉ cần thành viên đầu tiên của dữ liệu nội bộ của slice.

Đi unsafe.Pointer sẽ không truyền một lát tới con trỏ không an toàn, nhưng nó sẽ đưa con trỏ đến một lát như một con trỏ không an toàn. Vì tôi có thể tạo một con trỏ không an toàn cho bất kỳ kiểu con trỏ cũ nào mà tôi muốn, tôi có thể truyền con trỏ đến con trỏ trỏ tới một con trỏ, giúp khôi phục thành viên đầu tiên của dữ liệu nội bộ của slice.

Dưới đây là ví dụ hoạt động. Tôi muốn có một uintptr nhưng bạn có thể truyền cho bất kỳ loại con trỏ nào.

package main 

import (
    "fmt" 
    "unsafe" 
) 

func main() { 
    // Arbitrary size 
    n := 4 

    // Create a slice of the correct size 
    m := make([]int, n) 

    // Use convoluted indirection to cast the first few bytes of the slice 
    // to an unsafe uintptr 
    mPtr := *(*uintptr)(unsafe.Pointer(&m)) 

    // Check it worked 
    m[0] = 987 
    // (we have to recast the uintptr to a *int to examine it) 
    fmt.Println(m[0], *(*int)(unsafe.Pointer(mPtr))) 
} 

Nếu bạn muốn có một *int thay vào đó, bạn có thể làm mPtr := *(**int)(unsafe.Pointer(&m))

này hoạt động càng lâu càng một lát duy trì cấu trúc dữ liệu nội bộ này. Tôi chắc chắn mở cửa cho một giải pháp mạnh mẽ hơn mà không phụ thuộc vào cấu trúc của ruột của Go.

+2

Con trỏ đến phần tử sao lưu đầu tiên của m: = make ([] int, 10) slice là & m [0]. – alex

+0

Tệ của tôi. Tôi đã thử những gì tôi nghĩ là & m [0] trước đây, và đã nhận được một con trỏ đến một bản sao của những gì đã ở m [0]. Rõ ràng là tôi đã làm điều gì đó sai, bởi vì thử nó ngay bây giờ, nó hoạt động tốt. – chowey

Các vấn đề liên quan