So I'm writing a linked list in Ada - a pretty simple task. In the list.ads file, I declare a list node like so:
type Node;
type Node_Ptr is access Node;
type Node is record
Data: Integer;
Next: Node_Ptr;
end record;
In the adb file, I declare the head node as a sentinel:
Head: Node_Ptr := new Node_Ptr'(null, null);
From what I've read and seen, this should work. However, when I try to compile, it tells me that "expected type Node declared in list.ads", even though I already defined the type. Weirdly enough, it tells me that Node_Ptr is appropriately defined, but Node is not. What gives?
The line with the error is
Head: Node_Ptr := new Node_Ptr'(null, null);
The error message that GNAT GPL 2014 gives is
list.adb:2:34: expected type "Node" defined at list.ads:5
list.adb:2:34: found type "Node_Ptr" defined at list.ads:3
which is pointing at the ’ after the last character of Node_Ptr; the compiler has seen Head : Node_Ptr := new and is expecting the type Node.
In contrast, GCC 4.9.1 says
list.adb:2:35: expected type "Node_Ptr" defined at list.ads:3
list.adb:2:35: found a composite type
pointing at the opening paren of (null, null); it has seen the Node_Ptr’ and parsed the (null, null) sufficiently to see that it’s a composite type and can’t possibly be a value compatible with Node_Ptr.
As has already been said, the correct way of allocating a value is
FP : Foo_Ptr := new {value of type Foo};
or in your case
Head : Node_Ptr := new Node'(null, null);
.. but that fails on both compilers with
list.adb:2:33: expected type "Standard.Integer"
list.adb:2:33: found an access type
pointing at the first null.
I think you can probably fix it from there.
Related
I'm using cgo to write a service using a C library that we're using. I'm new to Go.
I'm having a runtime error on the following line:
status = int(C.VeProtect(C.VeObj(fpeProtect), &argsProtect))
The trace I get is:
panic serving [::1]:55146: runtime error: cgo argument has Go pointer to Go pointer
goroutine 20 [running]:
net/http.(*conn).serve.func1()
/usr/local/go/src/net/http/server.go:1801 +0x13a
panic({0xc21cc0, 0xc000093700})
/usr/local/go/src/runtime/panic.go:1047 +0x262
voltagems/voltagefuncs.protectAndAccess.func1(0x0, 0xc0000b2960)
/media/sf_winhome/git/voltagego/voltagefuncs/voltagefuncs.go:71 +0x90
First, I can't even tell from this which argument it's talking about, although I would guess it's the first one.
The type of "fpeProtect is "C.VeFPE", and the type of that is "*_Ctype_struct_VeFPE_st". That struct type has a handful of "_Ctype_int" properties, and several "*_Ctype_char" properties. I didn't directly set any properties of that object, it was passed to a couple of C methods that would have populated some of the fields.
If I understand it correctly, the implication of that error message is that one or more properties of that struct is a pointer to a Go object, not a C object. I don't see how that could be possible, but I also can't tell exactly what property it's complaining about.
Update:
#JimB made me realize that the issue is likely with the second parameter, not the first. I think that's correct, but the assignments associated with that were already complex.
These are the assignments in question:
argsProtect.plaintext = (*C.uchar)(&([]byte)(data)[0])
argsProtect.plaintextSize = C.uint(len(data))
const BufSize int = 256
var textBuffer []byte = make([]byte, BufSize)
argsProtect.ciphertext = (*C.uchar)(&textBuffer[0])
The "data" variable is type "string". The type of both "plaintext" and "ciphertext" is "*_Ctype_uchar".
How can I convert those "plaintext" and "ciphertext" assignments to fulfill the requirement of producing a "*C.uchar", but converting the GoPointer to a CPointer?
Update:
I think I may have fixed the ciphertext assignment, but I think the plaintext assignment needs to be fixed also. Here is the changed block:
argsProtect.plaintext = (*C.uchar)(&([]byte)(data)[0])
argsProtect.plaintextSize = C.uint(len(data))
const BufSize int = 256
textBuffer := C.malloc(C.ulong(C.sizeof_char * BufSize))
argsProtect.ciphertext = (*C.uchar)(textBuffer)
argsProtect.ciphertextBufferSize = C.uint(BufSize)
status = int(C.VeProtect(C.VeObj(fpeProtect), &argsProtect))
This still fails on the last line with "cgo argument has Go pointer to Go pointer".
I have a structure in C and I called that structure in my go program. If that structure throws any error it terminates my go program like below
orderbook.h
-------------
#ifndef _ORDERBOOK_H
#define _ORDERBOOK_H
typedef struct order order;
struct order {
int tradeid;
int side;
int symbol;
double amount;
double price;
};
orderbook.c
--------------
include "orderbook.h"
order* order_place(char *side,double amount,double price,char symbol[19])
{
struct order *tradeorder= calloc(1000000,sizeof(struct order));//Initlize the structure
//My internal code which place an order
clob_ord_t o=unxs_order(c, (clob_ord_t){CLOB_TYPE_LMT,parsed_side, amount, .lmt =price, .usr = (uintptr_t)out},NANPX);
if (o.qty.dis + o.qty.hid > 0.dd) {
/* put remainder of order into book */
i = clob_add(c, o);
//printf("orderid..%lu\n", i.usr);
printf("orderid..%s\n", i.usr);
insertMap(hashTable, i.usr, i);
// printMap(hashTable);
flag=true;
tradeorder[0].orderstatus=1;
tradeorder[0].orderid=offerid;
tradeorder[0].side=sid;
tradeorder[0].symbol=atoi(symbol);
tradeorder[0].amount=(double)o.qty.dis;
tradeorder[0].price=price;
}
return tradeorder; //return the structure
}
main.go
---------
o:=C.order_place(C.CString("ASK"),C.double(12.0),C.double(1.0),C.CString("1")) //this line may get an exception If some wrong parameter to pass otherwise returns correct value
If I put correct parameter to order_pace function from go there is no issue, If I pass some incorrect parameter then In get an exception an it terminates the go server. Now I need to handle that exception so that my server remain running irrespective of an exception.
You can't catch the fatal fault, and it isn't safe to continue after your C code throws a fault (unlike Go). The running program is in an undefined potentially dangerous state. The safest thing to do is shutdown the program and/or let it crash.
You must check for errors within C.order_place and return an error on failure. Eg, return NULL.
A few other recommendations:
Allocate struct order via Go to rely on the garbage collector to simplify memory management.
var order C.struct_order
C.order_place(&order, side, ...)
Always free strings allocated via C.CString once they are no longer needed.
cstr := C.CString("test")
C.free(unsafe.Pointer(cstr))
Depending on your platform, you can simplify debugging with improved stack traces by importing cgosymbolizer. This adds support for C stack traces.
import _ "github.com/ianlancetaylor/cgosymbolizer"
You probably should use char *symbol instead of char symbol[19] in your example since C.CString returns a pointer to an arbitrarily long C string, not a pointer to an array of 19 chars.
We use a third party Tcl parsing library to validation Tcl script for both syntax and semantic checking. The driver was written in C and defined a set of utility functions. Then it calls Tcl_CreateObjCommand so the script could call these C functions. Now we are in the process of porting the main program to go and I could not find a way to do this. Anyone know a way to call golang functions from Tcl script?
static int
create_utility_tcl_cmds(Tcl_Interp* interp)
{
if (Tcl_CreateObjCommand(interp, "ip_v4_address",
ip_address, (ClientData)AF_INET, NULL) == NULL) {
TCL_CHECKER_TCL_CMD_EVENT(0, "ip_v4_address");
return -1;
}
.....
return 0;
}
Assuming you've set the relevant functions as exported and built the Go parts of your project as in
Using Go code in an existing C project
[…]
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
Then the core of what remains to be done is to write the C glue function from Tcl's API to your Go code. That will involve a function something like:
static int ip_address_glue(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
// Need an explicit cast; ClientData is really void*
GoInt address_family = (GoInt) clientData;
// Check for the right number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "address");
return TCL_ERROR;
}
// Convert the argument to a Go string
GoString address;
int len;
address.p = Tcl_GetStringFromObj(objv[1], &len);
address.n = len; // This bit is hiding a type mismatch
// Do the call; I assume your Go function is called ip_address
ip_address(address_family, address);
// Assume the Go code doesn't fail, so no need to map the failure back to Tcl
return TCL_OK;
}
(Credit to https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf for providing enough information for me to work out some of the type bindings.)
That's then the function that you register with Tcl as the callback.
Tcl_CreateObjCommand(interp, "ip_v4_address", ip_address_glue, (ClientData)AF_INET, NULL);
Theoretically, a command registration can fail. Practically, that only happens when the Tcl interpreter (or a few critical namespaces within it) is being deleted.
Mapping a failure into Tcl is going to be easiest if it is encoded at the Go level as an enumeration. Probably easiest to represent success as zero. With that, you'd then do:
GoInt failure_code = ip_address(address_family, address);
switch (failure_code) {
case 0: // Success
return TCL_OK;
case 1: // First type of failure
Tcl_SetResult(interp, "failure of type #1", TCL_STATIC);
return TCL_ERROR;
// ... etc for each expected case ...
default: // Should be unreachable, yes?
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unexpected failure: %d", failure_code));
return TCL_ERROR;
}
Passing back more complex return types with tuples of values (especially a combination of a success indicator and a “real” result value) should also be possible, but I've not got a Go development environment in order to probe how they're mapped at the C level.
I'm trying to implement a red/black tree in Linux per task_struct using code from linux/rbtree.h. I can get a red/black tree inserting properly in a standalone space in the kernel such as a module but when I try to get the same code to function with the rb_root declared in either task_struct or task_struct->files_struct, I get a SEGFAULT everytime I try an insert.
Here's some code:
In task_struct I create a rb_root struct for my tree (not a pointer).
In init_task.h, macro INIT_TASK(tsk), I set this equal to RB_ROOT.
To do an insert, I use this code:
rb_insert(&(current->fd_tree), &rbnode);
This is where the issue occurs.
My insert command is the standard insert that is documented in all RBTree documentation for the kernel:
int my_insert(struct rb_root *root, struct mytype *data)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
/* Figure out where to put new node */
while (*new) {
struct mytype *this = container_of(*new, struct mytype, node);
int result = strcmp(data->keystring, this->keystring);
parent = *new;
if (result < 0)
new = &((*new)->rb_left);
else if (result > 0)
new = &((*new)->rb_right);
else
return FALSE;
}
/* Add new node and rebalance tree. */
rb_link_node(&data->node, parent, new);
rb_insert_color(&data->node, root);
return TRUE;
}
Is there something I'm missing?
Some reason this would work fine if I made a tree root outside of task_struct? If I make rb_root inside of a module this insert works fine. But once I put the actual tree root in the task_struct or even in the task_struct->files_struct, I get a SEGFAULT. Can a root node not be added in these structs?
Any tips are greatly appreciated. I've tried nearly everything I can think of.
Edit:
I get a SEGFAULT on the following line when trying to print and any line that accesses the tree. With this line you should get the understanding of how I'm handling the pointers. rb_entry and rb_first are methods already available in the kernel. current is a pointer to a task struct (current working process) and tree is my root node (not a pointer) which is a member of the task struct (I added). rb_first needs to pass a pointer *rb_root. I'm doing this wrong.
printk(KERN_CRIT "node=%d\n", rb_entry(rb_first(&(current->tree)), struct rb_tree_struct, node)->fd_key);
Could it be the pointer values of root and/or data aren't what you expect? It might be useful to add
printk("%s: root=%p data=%p\n", __func__, root, data);
before the while() loop.
Why does the following code throw an exception when getting to the second scanf_s after entering an number to put into the struct.
This by no means represents a complete linked list implementation.
Not sure how to get onto the next scanf_s when having entered the value? Any ideas?
EDIT: Updated code with suggested solution, but still get an AccessViolationException after first scanf_s
Code:
struct node
{
char name[20];
int age;
float height;
node *nxt;
};
int FillInLinkedList(node* temp)
{
int result;
temp = new node;
printf("Please enter name of the person");
result = scanf_s("%s", temp->name);
printf("Please enter persons age");
result = scanf_s("%d", &temp->age); // Exception here...
printf("Please enter persons height");
result = scanf_s("%f", &temp->height);
temp->nxt = NULL;
if (result >0)
return 1;
else return 0;
}
// calling code
int main(array<System::String ^> ^args)
{
node temp;
FillInLinkedList(&temp);
...
You are using scanf_s with incorrect parameters. Take a look at the examples in the MSDN documentation for the function. It requires that you pass in the size of the buffer after the buffer for all string or character parameters. So
result = scanf_s("%s", temp->name);
should be:
result = scanf_s("%s", temp->name, 20);
The first call to scanf_s is reading garbage off the stack because it is looking for another parameter and possibly corrupting memory.
There is no compiler error because scanf_s uses a variable argument list - the function doesn't have a fixed number of parameters so the compiler has no idea what scanf_s is expecting.
You need
result = scanf_s("%d", &temp->age);
and
result = scanf_s("%f", &temp->height);
Reason is that sscanf (and friends) requires a pointer to the output variable so it can store the result there.
BTW, you have a similar problem with the parameter temp of your function. Since you're changing the pointer (and not just the contents of what it points to), you need to pass a double pointer so that the changes will be visible outside your function:
int FillInLinkedList(node** temp)
And then of course you'll have to make the necessary changes inside the function.
scanf() stores data into variables, so you need to pass the address of the variable (or its pointer)Example:
char string[10];
int n;
scanf("%s", string); //string actually points to address of
//first element of string array
scanf("%d", &n); // &n is the address of the variable 'n'
%19c should be %s
temp->age should be &temp-age
temp->height should be &temp->height
Your compiler should be warning you
about these errors
I believe you need to pass parameters to scanf() functions by address. i.e. &temp->age
otherwise temp-age will be interpreted as a pointer, which will most likely crash your program.