0

I am trying to simulate the memcpy from C in Go using unsafe.Pointer. I have to map a string into a struct of strings in the following way:

package main

import (
    "fmt"
    "unsafe"
)

type myMessage struct {
    Field1 [30]string
    Field2 [2]string
    Field3 [4]string
    Field4 [1]string
    Field5 [1]string
}

func main() {

    var inputString string = "Abcdefghi"

    inputPtr := &inputString

    unsafePtr := unsafe.Pointer(inputPtr)

    messPtr := (*myMessage)(unsafePtr)

    var messageString myMessage = *messPtr

    fmt.Println(messageString)
}

The result is as following:

./test
{[Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi  Abcdefghi ] [Abcdefghi ] [Abcdefghi  Abcdefghi ] [Abcdefghi] []}

i.e. the code is copying inputString in each position of the final struct.

Why is the inputString duplicated?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Chiara
  • 17
  • 2

1 Answers1

3

You are not reserving enough memory for your struct value. The struct value is 38 strings longs, but you "copy" only one string. Consequently the remaining 37 strings reflect random memory after your first string, and it happens to be copies of the first string.

Reserve enough space for the struct and it works as expected:

package main

import (
        "fmt"
        "unsafe"
)

type myMessage struct {
        Field1 [30]string
        Field2 [2]string
        Field3 [4]string
        Field4 [1]string
        Field5 [1]string
}

func main() {
        var mem [38]string
        mem[0] = "Abcdefghi"

        fmt.Println("Sizeof(string) =", unsafe.Sizeof(""))
        fmt.Println("Sizeof(myMessage) =", unsafe.Sizeof(myMessage{}))
        fmt.Println("Sizeof(mem) =", unsafe.Sizeof(mem))

        unsafePtr := unsafe.Pointer(&mem)
        messPtr := (*myMessage)(unsafePtr)

        var messageString myMessage = *messPtr
        fmt.Println(messageString)
}

// Output:
// Sizeof(string) = 16
// Sizeof(myMessage) = 608
// Sizeof(mem) = 608
// {[Abcdefghi                             ] [ ] [   ] [] []}

Try it on the playground: https://play.golang.org/p/K3N-TnBbaLP

Peter
  • 29,454
  • 5
  • 48
  • 60
  • this code writes all the the mem string into the first char of the [30]string (Field1) expanding the length of Field1 of len(mem). instead, the desired result it to spread mem into the final struct – Chiara Aug 29 '18 at 10:56
  • Not sure how you come to that conclusion. The size of Field1 does not change: https://play.golang.org/p/TWa3ROOV9LD. And the *length* of the field is immutable anyway (30), because it's part of its type. I feel I misunderstand your goal here. If the output of the code isn't what you expect, could you add the expected result to the question? – Peter Aug 29 '18 at 13:57