What you're doing is not correct. For the last member of world to be an array of N hellos, it has to be of type hello * N, not hello.
But here, N is 0, so that doesn't really work.
In C, this is called the "struct hack" or "struct array hack". That world struct isn't a real structure that you can construct as-is and pass around. Instead, what you do is malloc up sizeof(world) + N * sizeof(hello) bytes, cast that to world *, and pass that pointer around. Because array indexing doesn't do any type-checking in C, my_world->h[2] will just work (assuming you've allocated enough memory for at least 3 hellos at the end of the world).
But it won't work in Python.
Well, it sort of works, but you have to do more work.
The first option is to not actually define world globally, and instead define a new Structure class every time you want to deal with a world.
For example. let's say we called some function that told us how many hellos there are:
n = lib.number_of_hellos()
And now we want to call a function that gives us the world with that many hellos in it. So:
class world(Structure):
_pack_ = 1
_fields_ = [ ("f1", c_ulonglong),
("f2", c_ulonglong),
("f3", c_uint16),
("f4", c_uint16),
("f5", c_uint32),
("f6", hello * n)
]
At this point, you can either change the restype of lib.get_world to return a POINTER(world), or you can cast the result that comes back.
Alternatively, you can define world as always having 1 hello, but then, instead of accessing hello directly off a world pointer, you construct a hello * N pointer at the hello's address (or just at the world's address plus the offset of the type's hello; either way is the same).
What if you need to create a world with N hellos in it to pass to C?
You can use the first trick again, constructing a new world class that ends with an array of N hellos, then create an instance of that to pass it to C.
Or you can use the same trick C code uses: keep the global single-hello world class around, and either construct your world objects by creating a buffer and then casting that to a world, or by constructing a world object but then calling resize on it.
There are also workarounds you can do to make life easier. For example, if you're writing the C code yourself (and you can't just not use the struct hack), you can easily add a pair of C functions that compose a no-hello world, an array of hellos, and a count into an N-hello world, and vice-versa.
Or, alternatively, just make a nonhackyworld type that has a pointer to an array of hellos at the end, instead of directly including it, and write C functions to convert back and forth between them.
Then you just ctypes up those functions and call them whenever you want to pass or process a world (or even set them up as value type converters for other functions).
Even if you can't add C functions, you can write those functions in ctypes. They'll be horribly ugly messes of creating buffers and casting pointers, but you only have to write them (and debug the segfaults) once, and then use them everywhere.