CGO converts the go-code you wrote (using the C import), into valid go function calls, pointers, structs, and variables. It also provides C-code that converts between go's runtime conventions and C's. For every value, pointer, and struct, an equivalent go type is made, so the memory is used directly. The important thing to take out of this is that the go code it produces is in no way special compared to any you'd write.
Go doesn't have unions, and go structs can't have fields that alias other fields, so C unions can not be represented by an "equivalent" type. They are instead treated as a block of memory in the form of a byte array.
If you run "go tool cgo main.go" you will see in _obj/_cgo_gotypes.go that C.B is defined as "type _Ctype_union__B [4]byte".
You must use a unsafe.Pointer cast to read/write the appropriate type. eg:
ptr := (*int32)(unsafe.Pointer(&a.b[0]))
*ptr = 42