Displayed size of Go string variable seems unreal - memory-management

Please see the example: http://play.golang.org/p/6d4uX15EOQ
package main
import (
"fmt"
"reflect"
"unsafe"
)
func main() {
c := "foofoofoofoofoofofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo"
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c))
fmt.Printf("c: %T, %d\n", c, reflect.TypeOf(c).Size())
}
Output:
c: string, 8 //8 bytes?!
c: string, 8
It seems like so large string can not have so small size! What's going wrong?

Package unsafe
import "unsafe"
func Sizeof
func Sizeof(v ArbitraryType) uintptr
Sizeof returns the size in bytes occupied by the value v. The size is
that of the "top level" of the value only. For instance, if v is a
slice, it returns the size of the slice descriptor, not the size of
the memory referenced by the slice.
The Go Programming Language Specification
Length and capacity
len(s) string type string length in bytes
You are looking at the "top level", the string descriptor, a pointer to and the length of the underlying string value. Use the len function for the length, in bytes, of the underlying string value.
Conceptually and practically, the string descriptor is a struct containing a pointer and a length, whose lengths (32 or 64 bit) are implementation dependent. For example,
package main
import (
"fmt"
"unsafe"
)
type stringDescriptor struct {
str *byte
len int
}
func main() {
fmt.Println("string descriptor size in bytes:", unsafe.Sizeof(stringDescriptor{}))
}
Output (64 bit):
string descriptor size in bytes: 16
Output (32 bit):
string descriptor size in bytes: 8

A string is essentially a pointer the the data, and an int for the length; so on 32bit systems, it's 8 bytes, and 16 bytes on 64-bit systems.

Both unsafe.Sizeof and reflect.TypeOf(foo).Size() show the size of the string header (two words, IIRC). If you want to get the length of a string, use len(foo).
Playground: http://play.golang.org/p/hRw-EIVIQg.

Related

How do you convert array of byte to array of float64

I am searching to convert an array of byte ([]byte) to array of float64 ([]float64) but I didn't have any clues to do it.
I read data from rtlsdr package (https://pkg.go.dev/github.com/jpoirier/gortlsdr) and would pass it to Pwelch algorithm (https://pkg.go.dev/github.com/mjibson/go-dsp/spectral)
Is it possible to convert large array of byte to float64 ?
(+ another question: did you think that possible to convert Pwelch function to work with uint8 ?)
Thank you so much,
pefr
byte/uint8 has 8 bits, float64 has 64. You can convert [8]byte to float64 like this:
package main
import (
"encoding/binary"
"fmt"
"math"
)
main()
{
in := 1.
// Convert float64 to [8]byte
var bytes [8]byte
binary.LittleEndian.PutUint64(bytes[:], math.Float64bits(in))
// Convert [8]byte to float64
out := math.Float64frombits(binary.LittleEndian.Uint64(bytes[:]))
fmt.Println(out)
}
You may want to chose binary.BigEndian instead.
Is that what you are looking for? Or do you want to convert an array of byte with length 8n to an array of float64 with length n? Feel free to comment :-)

which type's size is zero in slice of golang?

which type's size is zero in slice of golang?
When I read the source code of golang slice, I found a code et.size == 0. so I want to know which type's size is 0?
func growslice(et *_type, old slice, cap int) slice {
...
if et.size == 0 {
if cap < old.cap {
panic(errorString("growslice: cap out of range"))
}
return slice{unsafe.Pointer(&zerobase), old.len, cap}
}
...
}
The Go Programming Language Specification
Size and alignment guarantees
A struct or array type has size zero if it contains no fields (or
elements, respectively) that have a size greater than zero. Two distinct
zero-size variables may have the same address in memory.
For example,
package main
import (
"fmt"
"unsafe"
)
func main() {
type zero struct{}
fmt.Println(unsafe.Sizeof(zero{}))
slice := make([]zero, 7)
fmt.Printf("%d %v %p %p\n", len(slice), slice, &slice[0], &slice[len(slice)-1])
}
Playground: https://play.golang.org/p/pn8Rz0IorwD
Output:
0
7 [{} {} {} {} {} {} {}] 0x1c4c84 0x1c4c84

Why these two structs have different size in the memory?

Suppose I have these two structs:
package main
import (
"fmt"
"unsafe"
)
type A struct {
int8
int16
bool
}
type B struct {
int8
bool
int16
}
func main() {
fmt.Println(unsafe.Sizeof(A{}), unsafe.Sizeof(B{})) // 6 4
}
Size of A is 6 bytes. however, the size of B is 4 bytes.
I assume that it's related to their layout in the memory, but I'm not sure I understand why it's behave like this.
Isn't something that the compiler can detect and optimize? (rearrange the fields order)
Link to the code
Padding due to alignment.
The Go Programming Language Specification
Size and alignment guarantees
For the numeric types, the following sizes are guaranteed:
type size in bytes
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16
The following minimal alignment properties are guaranteed:
For a variable x of any type: unsafe.Alignof(x) is at least 1.
For a variable x of struct type: unsafe.Alignof(x) is the largest of all the values unsafe.Alignof(x.f) for each field f of x, but at least
1.
For a variable x of array type: unsafe.Alignof(x) is the same as the alignment of a variable of the array's element type.
A struct or array type has size zero if it contains no fields (or
elements, respectively) that have a size greater than zero. Two
distinct zero-size variables may have the same address in memory.
For example,
package main
import (
"fmt"
"unsafe"
)
type A struct {
x int8
y int16
z bool
}
type B struct {
x int8
y bool
z int16
}
func main() {
var a A
fmt.Println("A:")
fmt.Println("Size: ", unsafe.Sizeof(a))
fmt.Printf("Address: %p %p %p\n", &a.x, &a.y, &a.z)
fmt.Printf("Offset: %d %d %d\n", unsafe.Offsetof(a.x), unsafe.Offsetof(a.y), unsafe.Offsetof(a.z))
fmt.Println()
var b B
fmt.Println("B:")
fmt.Println("Size: ", unsafe.Sizeof(b))
fmt.Printf("Address: %p %p %p\n", &b.x, &b.y, &b.z)
fmt.Printf("Offset: %d %d %d\n", unsafe.Offsetof(b.x), unsafe.Offsetof(b.y), unsafe.Offsetof(b.z))
}
Playground: https://play.golang.org/p/_8yDMungDg0
Output:
A:
Size: 6
Address: 0x10410020 0x10410022 0x10410024
Offset: 0 2 4
B:
Size: 4
Address: 0x10410040 0x10410041 0x10410042
Offset: 0 1 2
You may be matching an external struct, perhaps in another language. It's up to you to tell the compiler what you want. The compiler doesn't guess.

Size of a byte array golang

I have a []byte object and I want to get the size of it in bytes. Is there an equivalent to C's sizeof() in golang? If not, Can you suggest other ways to get the same?
To return the number of bytes in a byte slice use the len function:
bs := make([]byte, 1000)
sz := len(bs)
// sz == 1000
If you mean the number of bytes in the underlying array use cap instead:
bs := make([]byte, 1000, 2000)
sz := cap(bs)
// sz == 2000
A byte is guaranteed to be one byte: https://golang.org/ref/spec#Size_and_alignment_guarantees.
I think your best bet would be;
package main
import "fmt"
import "encoding/binary"
func main() {
thousandBytes := make([]byte, 1000)
tenBytes := make([]byte, 10)
fmt.Println(binary.Size(tenBytes))
fmt.Println(binary.Size(thousandBytes))
}
https://play.golang.org/p/HhJif66VwY
Though there are many options, like just importing unsafe and using sizeof;
import unsafe "unsafe"
size := unsafe.Sizeof(bytes)
Note that for some types, like slices, Sizeof is going to give you the size of the slice descriptor which is likely not what you want. Also, bear in mind the length and capacity of the slice are different and the value returned by binary.Size reflects the length.

With Go, how to append unknown number of byte into a vector and get a slice of bytes?

I'm trying to encode a large number to a list of bytes(uint8 in Go).
The number of bytes is unknown, so I'd like to use vector.
But Go doesn't provide vector of byte, what can I do?
And is it possible to get a slice of such a byte vector?
I intends to implement data compression.
Instead of store small and large number with the same number of bytes,
I'm implements a variable bytes that uses less bytes with small number
and more bytes with large number.
My code can not compile, invalid type assertion:
1 package main
2
3 import (
4 //"fmt"
5 "container/vector"
6 )
7
8 func vbEncodeNumber(n uint) []byte{
9 bytes := new(vector.Vector)
10 for {
11 bytes.Push(n % 128)
12 if n < 128 {
13 break
14 }
15 n /= 128
16 }
17 bytes.Set(bytes.Len()-1, bytes.Last().(byte)+byte(128))
18 return bytes.Data().([]byte) // <-
19 }
20
21 func main() { vbEncodeNumber(10000) }
I wish to writes a lot of such code into binary file,
so I wish the func can return byte array.
I haven't find a code example on vector.
Since you're trying to represent large numbers, you might see if the big package serves your purposes.
The general Vector struct can be used to store bytes. It accepts an empty interface as its type, and any other type satisfies that interface. You can retrieve a slice of interfaces through the Data method, but there's no way to convert that to a slice of bytes without copying it. You can't use type assertion to turn a slice of interface{} into a slice of something else. You'd have to do something like the following at the end of your function: (I haven't tried compiling this code because I can't right now)
byteSlice = make([]byte, bytes.Len())
for i, _ := range byteSlice {
byteSlice[i] = bytes.At(i).(byte)
}
return byteSlice
Take a look at the bytes package and the Buffer type there. You can write your ints as bytes into the buffer and then you can use the Bytes() method to access byte slices of the buffer.
I've found the vectors to be a lot less useful since the generic append and copy were added to the language. Here's how I'd do it in one shot with less copying:
package main
import "fmt"
func vbEncodeNumber(n uint) []byte {
bytes := make([]byte, 0, 4)
for n > 0 {
bytes = append(bytes, byte(n%256))
n >>= 8
}
return bytes
}
func main() {
bytes := vbEncodeNumber(10000)
for i := len(bytes)-1; i >= 0 ; i-- {
fmt.Printf("%02x ", bytes[i])
}
fmt.Println("")
}

Resources