cgo: errno with Go 1 (weekly)

495 views
Skip to first unread message

Rob Thornton

unread,
Feb 11, 2012, 6:08:22 PM2/11/12
to golang-nuts
I'm having an issue with converting my library to weekly/Go 1.
Overall, the new error system seems far better than the old. However,
I am having an issue trying to get the errno value for custom errors.

1. Specifically, ncurses doesn't (to my knowledge) map error strings
for its errno values. It would be possible to use strerror_r to set
them but it seems easier to just map the error codes to their related
strings. Either way, I still need to test again C.E_OK or for another
error value. How can I convert the error type to the errno value
assigned to it? I couldn't find anything in the weekly documentation
about it (nor in any web searches).

Hypothetical example:

package main

// #include <errno.h>
// #define MYERROR 0xFF
// int fun() { errno = MYERROR; return 1; }
import "C"

import (
"fmt"
)

func main() {
_, err := C.fun();
if err != 0 { // error, mismatched types error and int (obviously)
fmt.Println("FAIL!: My Error occured!")
}
}

2. My second issue is that you can't get an errno value from a void
function. It only works with functions that return a value.

Outside of that, I love the new changes.

Sindre Myren

unread,
Feb 15, 2012, 10:14:45 AM2/15/12
to Rob Thornton, golang-nuts
Hmm.. Yeah that last email wasn't realy helpfull I suppose. Sorry.

You have to do if err != nil, and not if err != 0.

Other then that I haven't found any simple way of extracting the errno - except for parsing the output from err.Error(), which is an option. By doing this, you wold have to use the "errno xxx" as a key in your errno2error-message map, and not the errno itself.



package main

// #include <errno.h>
// #define MYERROR 0xFF
// int fun() { errno = MYERROR; return 1; }
import "C"
import "fmt"

func main() {
        n, err := C.fun()
        fmt.Println(n)
        fmt.Println(err)
        if err != nil {
                fmt.Println(err.Errno)
        }
}



Den 14:39 15. februar 2012 skrev Sindre Myren <smy...@gmail.com> følgende:
Here is an example of how I handle errors from c code. Other simpler methods are also possible, e.g you do not have to define your own error type. You could just user errors.New() instead.

// #cgo CFLAGS: -std=gnu99 -I../../../build/include
// #cgo LDFLAGS: -L../../../build/lib/eurobot -lmotor -lcanopen -lsocketcan
// #include <eurobot/motor.h>
import "C"


/* Error struct */

const (
        ERR_FAULT   = -1
        ERR_TIMEOUT = -2
)

type Error struct {
        s string
        code int
}

func NewError(code int, s string) (e *Error) {
        e = new(Error)
        e.code = code
        e.s = s
        return
}

func (e *Error)Error() string {
        return e.s
}

func (e *Error)Type() int {
        return e.code
}

...

func Connect() {
        cerr := C.motor_init()
        if int(cerr) != 0 {
                panic("motor: Initialization failed!")
        }
}


...

func Start() (err error) {
        cerr := int(C.motor_start())
        if cerr < 0 {
                err = NewError(ERR_FAULT, "motor: Start: Could not send message")
        }
        return
}

Rob Thornton

unread,
Feb 17, 2012, 1:01:48 AM2/17/12
to golang-nuts
Thanks to the fix committed today, errno now seems to function with
values outside the range of those used by the standard libraries (I've
only tested it with my simple use test). However, retrieving the value
is still difficult. The solution I've used thus far is to split the
error string, then convert the errno value to integer, then test the
integer against the C errno values from the library.

To me it would be far simpler to simply add another function, Value(),
to retrieve the errno value similar to how the original implementation
did it:

_, errno := C.somecfun()

if errno.Value() != int(C.SOMEERR) {
// Print error string
}

If the error does NOT contain an Errno value then 0 would be
returned.

I wasn't sure if this was something I should file a bug report on,
however, in case there WAS a simple way to get the value from error
that I've somehow overlooked.

Rob

Rob Thornton

unread,
Feb 17, 2012, 10:13:18 AM2/17/12
to golang-nuts
The answer was given to me via the issue tracker:

"The error is a syscall.Error.

if errno, ok := err.(syscall.Error); ok {
   fmt.Println("the error is", int(errno))
}"

Exactly what I was looking for!
Reply all
Reply to author
Forward
0 new messages