Posts tagged ‘C’

ctypes and flexible (zero-length) arrays

Dear lazyweb, I’ve been racking my brain trying to get information out of the following C struct in a nice way when using ctypes:

struct Foo
{
    unsigned int length;
    char name[];
};

I wrote a little C function to get instance of the struct easily into python:

struct Foo *
put_name(char *name)
{
    struct Foo *foo = malloc(sizeof(struct Foo) + strlen(name));
    foo->length = strlen(name);
    memcpy(foo->name, name, foo->length);
    return(foo);
}

Now, how do I actually get the full contents of Foo.name in python? The only way I could think of that actually works is to create a dummy-struct type in order to get the length out and then use it to dynamically create a new sub-class of ctypes.Structure, then create an instance based on the address of what was returned. I think the following shows it pretty clearly:

class FOO(Structure):
    _fields_ = [('length', c_uint), ('name', c_char * 0)]

liblib = cdll.LoadLibrary(’./_build/liblib.so’)
c_put_name = liblib.put_name
c_put_name.argtypes = [c_char_p]
c_put_name.restype = POINTER(FOO)

def put_name(str):
    f = c_put_name(str)
    K = type(’FOO%s’ % f.contents.length, (Structure,),
                        {’_fields_’ : [('length', c_uint), ('name', c_char * f.contents.length)]})
    return K.from_address(addressof(f.contents))

I still think there ought to be some other way that ‘feels’ nicer. I mean the use of “short arrays” (declared as here with [], or zero size as supported by GCC, or the more portable array of size one) seems to be common enough to warrant some support from ctypes, right?

Any suggestions for improvements?

Venting on C++

Lately I’ve used C++ for a tool I’ve been working on at the office. Here are some idiosyncrasies in the standard library that I’ve noticed:

I was expecting the following code to compile:

std::string f("hello.txt");
std::ifstream in_file(f);

But oh no! For some reason ifstream doesn’t have a constructor that accepts a standard C++ string. Instead I am forced to pass a const char * to the constructor, e.g.:

std::string f("hello.txt");
std::ifstream in_file(f.c_str());

I guess that’s an excellent exmple of standardisation-by-committee where one part of the committee doesn’t have a clue what the other one is doing. Pathetic, really!

Now more stuff on ifstream. One would hope that opening a non-existing file for reading would trigger some sort of exception, at the very least reading from a non-existing file shouldn’t succeed. Oh, but not so in the wonderful world of C++. The following code compiles and executes just fine even if the file (hello.txt) doesn’t exist:

std::ifstream inf("hello.txt");
std::string r;
inf >> r;
std::cout << r << std::endl;

r is unmodified by inf >> r;. Even more interestingly inf.eof() returns false. Interestingly inf.bad() returns false too. Luckily inf.good()i returns false too, so there is some way of finding out that not all is well with inf. It was also pointed out that evaluating inf itself, such as in if(inf) ..., also results in false.

Ah, now I feel much better :-)

  1. I can’t understand the reasonning behind having two methods, good() and bad() which aren’t each other’s opposites, their names certainly suggests they ought to be! It seems they are badly named, they should be called no_error_has_occured() and no_exceptional_failure_has_occured() respectively.[back]

Having fun with C++’s auto_ptr

Sometimes RAII is difficult.

The following code compiles without errors or warnings on Windows using Visual Studio 2005:

#include <iostream>
#include <memory>

namespace Test
{

    class Foo
    {
    public:
        bool should_do_stuff() { return false; }
    };

    class Bar
    {
    public:
        Bar(std::auto_ptr<Foo> fp) : _fp(fp) {}

        void do_stuff() {
            if(_fp->should_do_stuff())
                std::cout << "Do stuff" << std::endl;
            else
                std::cout << "Don't do stuff" << std::endl;
        }

    private:
        std::auto_ptr<Foo> _fp;
    };

} // Test


int
main()
{
    std::auto_ptr<Test::Foo> fp;
    fp = new Test::Foo;

    bp->do_stuff();

    return(0);
}

However, it throws an exception just at the end of execution. Hmm, strange. Compiling it using GCC fails—it complains about the lack of an applicable operator= function.

This is what the assignment should look like:

fp = std::auto_ptr<Test::Foo>(new Test::Foo);

With that change GCC accepts it, and Microsoft’s compiler generates exception-free code.

Banging my head against sparse files

Lately I’ve had use for sparse files to solve a problem. Simple, yes. Use lseek and write (or read). Even better, at least in this case, use pwrite and pread. Should be simple, right? Yes, should be.

I was banging my head against code equivalent to the following for quite a few hours:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = ‘a’;
    }

    int fd1;

    if(-1 == (fd1 = open(”file1″, O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, “open (test1)”);
    off = 0×80000000;
    printf(”size: %d\n”, sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, “pwrite (%lli)”, off);

    return(0);
}

Can you spot the problem?

Well, I can tell you it doesn’t work. off_t becomes 64-bit due to the #define _FILE_OFFSET_BITS 64 so the off variable isn’t negative in my code. Somehow however it becomes negative on the way into pwrite, and without a single compiler or linker error at that!

Have you spot the problem yet?

Here’s the correctly working code:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = ‘a’;
    }

    int fd1;

    if(-1 == (fd1 = open(”file1″, O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, “open (test1)”);
    off = 0×80000000;
    printf(”size: %d\n”, sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, “pwrite (%lli)”, off);

    return(0);
}

Don’t see any difference? Look at the list of included files!

Let me just say the C and I aren’t on speaking terms at the moment!