Access char[] variable from C language's structure to go - c

Here I have test.h header file and in this header file I have declared one char a[10] variable. I have created one test.c file which includes test.h and assigns "Test" as a value. Now I have main.go file which will use that variable. Below are my code details.
test.h: this my header file
#ifndef _TEST_H
#define _TEST_H
typedef struct student student;
struct student {
char a[10];
};
student* show();
#endif
test.c: C source file which access test.h file and assign that variable a[10] with "Test"
#include "test.h"
#include <string.h>
student* show()
{
struct student *s= malloc(sizeof(struct student) * 1);
strcpy(s[0].a,"Test");
return s;
}
main.go
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "test.h"
import "C"
import (
"fmt"
"unsafe"
)
func main() {
s:= C.show();
defer C.free(unsafe.Pointer(s))
sSlice := (*[1]C.struct_student)(unsafe.Pointer(s));
fmt.Println(sSlice);
for _, ss := range sSlice {
fmt.Printf("A...%s", ss.a) //Here I want to access that variable
}
}
But Instead of showing Test its showing &[{[84 101 115 116 0 0 0 0 0 0]}].

The %s format specifier for Go works with Go strings and Go slices and arrays whose element type has the underlying type byte (such as []byte).
The ss.a field, as converted by cgo, has the Go type [10]C.char.
On many platforms, C.char is a signed character type, while Go's byte is always unsigned. So it may be the case that C.char has the underlying Go type int8 instead of byte (uint8), in which case fmt cannot print it using %s. In order to print it, you need to change the type.
One simple way to do that is to make a copy using C.GoString. C.GoString expects a *C.char, which in this case is the address of ss.a[0]:
for _, ss := range sSlice {
s := C.GoString(&ss.a[0])
fmt.Printf("A...%s\n", s)
}
(In C, ss.a and &ss.a[0] are equivalent, because C more-or-less does not distinguish between arrays and pointers. However, in Go arrays and pointers are completely distinct types.)
If the string may be large, you might want to avoid copying the entire slice into the Go heap.
You can express the change of type using unsafe.Pointer and convert it to a slice using Go 1.17's unsafe.Slice:
for _, ss := range sSlice {
s := unsafe.Slice((*byte)((unsafe.Pointer)(&ss.a[0])), len(ss.a))
fmt.Printf("A...%s\n", s)
}
Or, you could use the ConvertAt function from my unsafeslice package to express it a bit more simply:
for _, ss := range sSlice {
var s []byte
unsafeslice.ConvertAt(&s, ss.a[:])
fmt.Printf("A...%s\n", s)
}

Related

multiple definition and making sure function is correctly written

This is my .h file
#ifndef _test_h_
#define _test_h_
void new_cmd(void);
void open_cmd(void);
void close_cmd(void);
void close_all_cmd(void);
void save_cmd(void);
void save_as_cmd(void);
void save_all_cmd(void);
void print_cmd(void);
void exit_cmd(void);
void call(char *cmd_name);
struct {
char *cmd_name;
void (*cmd_pointer)(void);
} file_cmd[] =
{
{"new", new_cmd},
{"open", open_cmd},
{"close", close_cmd},
{"save", save_cmd},
{"save as", save_as_cmd},
{"save all", save_all_cmd},
{"print", print_cmd},
{"exit", exit_cmd}};
#endif
This is my function file
void call(char *cmd_name){
int i;
scanf("Enter command: %c\n",cmd_name);
for(i = 0; i < sizeof(file_cmd); i++){
if(strcmp(cmd_name, file_cmd[i].cmd_name) == 0){
file_cmd[i].cmd_pointer();
}
}
I just deleted all file_cmd functions because it seems for other people
and this is my main file
#include <stdio.h>
#include <string.h>
#include "test.h"
int main(void){
char cmd;
call(cmd);
return 0;
}
More I want to know is that my function void call is correctly written.
when I try to compile, it says
expected 'char*' but argument is of type 'char'
multiple definition of 'file_cmd'
first define here.
I am so confused how to fix it.
Please help
thank you.
You have two very different errors that you really should have asked about in two different question, but I'll be nice and answer both anyway.
In the main function you have a variable named cmd. It is of type char. You pass it to the call function, which expects an argument of type char * (i.e. a null-terminated string).
To fix this you first need to make sure that cmd is the correct type (i.e. char * instead of plain char). Secondly you need to make sure this pointer is actually pointing to a valid null-terminated byte string.
In other words, something like this:
char *cmd = "open";
call(cmd);
C really only cares about translation units. A translation unit is a single source files with all included header files.
The problem here is that variables can only be defined in a single translation unit. And since you define the variable file_cmd in a header file that is included in multiple source files, it will be defined in both translation units created from those two source files.
The solution here is to only declare the variable in the header file, and define it in a single source file.
For example, do something like this in the header file
struct command_struct
{
char *cmd_name;
void (*cmd_pointer)(void);
};
extern struct command_struct file_cmd[];
Then in one source file (like your "function file")
struct command_struct file_cmd[] = {
// Your initialization...
};
There are also other problems with your code, some of them will lead to undefined behavior.
For example the sizeof operator returns the size in bytes, not the number of elements in an array. To get the number of elements in an array you need to divide the byte-size of the full array with the byte-size of a single element. For example sizeof file_cmd / file_cmd[0].
Do note that the division only works for real arrays, not pointers, and that arrays very easily decays to pointers (to their first element).

C - Accessing incomplete types in linked files

I have a problem where i am linking multiple files in C. I want to define a constant representing array length at compile time, but save the user having to implement this in their file every time.
Here's the gist:
data.h - defines some constants
extern const int data[];
extern const int DATA_SIZE;
//other functions, not relevant
int get_second_item(void);
library_data.c - implements some of the functions in data.h
#include "data.h"
const int DATA_SIZE = sizeof(data) / sizeof(data[0]);
//can't compile because data is an incomplete type and hasn't been defined yet
int get_second_item(void)
{
return data[1];
}
public_data.c - user changes this with their data.
#include "data.h"
const int data[] = {1, 2, 3};
library_data.c and data.h are compiled first as .o files, amongst other library files that #include data.h and need to therefore use DATA_SIZE. Moving
const int DATA_SIZE = sizeof(data) / sizeof(data[0])
to public_data.c will of course work, but isn't a neat solution.
You can't use sizeof on an extern array of unspecified size (e.g. extern const int data[];)
From http://c-faq.com/decl/extarraysize.html:
An extern array of unspecified size is an incomplete type; you cannot
apply sizeof to it. sizeof operates at compile time, and there is no
way for it to learn the size of an array which is defined in another
file.
You have three options:
Declare a companion variable, containing the size of the array, defined and initialized (with sizeof) in the same source file where
the array is defined:
file1.c: file2.c:
int array[] = {1, 2, 3}; extern int array[];
int arraysz = sizeof(array); extern int arraysz;
(See also question 6.23.)
#define a manifest constant for the size so that it can be used consistently in the definition and the extern declaration:
file1.h:
#define ARRAYSZ 3
extern int array[ARRAYSZ];
file1.c: file2.c:
#include "file1.h" #include "file1.h"
int array[ARRAYSZ];
Use some sentinel value (typically 0, -1, or NULL) in the array's last element, so that code can determine the end without an explicit
size indication:
file1.c: file2.c:
int array[] = {1, 2, 3, -1}; extern int array[];
One solution might be to add an initialization function to data.c, and then you'll have to make sure that when any programs are built the function is called to prepare the data size.
int initupdate_datasize() {
DATA_SIZE = sizeof(data) / sizeof(data[0]);
return 0;
}
You'll have to remove the const from the data.h, and library_data.c
Another way would be to pass a compiler define such as -DDATASZ=96 that you would get to all source files that need it. For any given platform you could update it manually if it rarely changes, or you could even create a test-datasize program, that would output the data size from the initupdate_datasize function (or a similar C macro instead.) Depending on your build system it should be possible to pass that parameter as a compiler define.
For example in a Makefile if you're using GNU make this might help:
DATA_SIZE = $(shell ./test-datasize)
CFLAGS = -O3 -Wall -DDATASZ=$(DATA_SIZE)

How to pass pointer to slice to C function in go

Background: using cgo to call C functions from Golang.
I want to use a C function which has this signature: int f(int *count, char ***strs).
It will modify the data of count and strs, which is the reason why it uses pointer to them.
The value of count is the length of strs; strs is an array of string; the return value is simply an (boolean) indicator which states whether there is an error or not.
In golang, I can successfully pass and modify count by using C.f((*C.int)(&count)); pass []string by using []*C.char. Sample code is like this:
/*
#include <stdio.h>
int f(int *c, char **str) {
int i;
printf("%d\n", *c);
for (i = 0; i < *c; i++) {
printf("%s\n", str[i]);
}
*c = (*c) + 1;
return 1;
}
*/
import "C"
func go_f(strs []string) int {
count := len(strs)
c_count := C.int(count)
c_strs := make([]*C.char, count)
for index, value := range strs {
c_strs[index] = C.CString(value)
defer C.free(unsafe.Pointer(c_strs[index]))
}
err := C.f(&c_argc, (**C.char)(&c_argv[0]))
return int(err)
}
As you can see, the C function is currently int f(int *c, char **str), but what I'd like is int f(int *c, char ***str).
This is to say: what I actually want is to enable the modification to the string array (e.g. resize) in C and turn it back to a Go string slice so I can still use it in Go.
How to do this? I've searched and experimented for a while but with no luck.
A Go slice is both allocated in Go, and a different data structure than a C array, so you can't pass it to a C function (cgo will also prevent you from doing this because a slice contains a Go pointer)
You need to allocate the array in C in order to manipulate the array in C. Just like with C.CString, you will also need to track where to free the outer array, especially if the C function may possibly allocate a new array.
cArray := C.malloc(C.size_t(c_count) * C.size_t(unsafe.Sizeof(uintptr(0))))
// convert the C array to a Go Array so we can index it
a := (*[1<<30 - 1]*C.char)(cArray)
for index, value := range strs {
a[index] = C.CString(value)
}
err := C.f(&c_count, (***C.char)(unsafe.Pointer(&cArray)))

Array of macros in C

Can I do array of macros
I am trying to define array of macros, Please check the below code and let me know can I do it like this:
#include <stdio.h> 
struct da
{
    unsigned char d1:1;
    unsigned char d2:1;
};
struct da stDataVar;
#define DATA_1 stDataVar.d1
#define DATA_2 stDataVar.d2 = 1
unisgned char arrChar[2] = {DATA_1, DATA_2};
main()
{
 
printf("data = %d\n",arrChar[0]);
}
It doesn't make any sense to have "an array of macros". In your case, the macros probably just obfuscate the code. In particular, you shouldn't hide side effects inside macros that you are using for initialization.
Is there any reason why you can't do like this?
// elsewhere in the code:
stDataVar.d2 = 1;
...
unsigned char arrChar[2] =
{
stDataVar.d1,
stDataVar.d2
};
arrChar[0] is the 1st element of arrChar[2] i.e. DATA_1 which is a macro that gets textually replaced by the preprocessor as stDataVar.d1 which is structure stDataVar(of type struct da)'s d1 bit field which is zero or garbage (depends on compiler if that initializes a character by default)

Multidimensional Slices in Go

I would like to have an array / slice in Go with a variadic number of elements (not known at compile time) and be able to dinamically add new elements of different types, for instance:
data[0] := "string"
data[1] // slice
data[1][0] := "another string"
data[1][1] := 42 // int
Is this possible somehow?
It's a bit ugly but possible using empty interfaces, interface{}:
package main
import "fmt"
func main() {
variadic := []interface{}{}
variadic = append(variadic, "foo")
variadic = append(variadic, []interface{}{"bar", 42})
//this will print "foo"
fmt.Println(variadic[0])
//note that you have to cast variadic[1] to an array before accessing it
fmt.Println(variadic[1].([]interface{})[0])
}
If you allow the assumption that each element must be an array of anything with varying length, it's a bit less ugly:
package main
import "fmt"
func main() {
variadic := [][]interface{}{}
variadic = append(variadic, []interface{}{"foo"})
variadic = append(variadic, []interface{}{"bar", 42})
fmt.Println(variadic[0])
fmt.Println(variadic[1][0])
fmt.Println(variadic[1][1])
}

Resources