tags:

views:

105

answers:

4

I have a struct like this:

typedef struct string {
 unsigned long length;
 unsigned *data;
} string;

Can I write something so that when I do this:

string s;

the length property is zero, instead of whatever happens to be in the memory? data works well, as it's preset to zero or a null pointer.

Example of what happens right now:

string s;
printf("length:  %lu\n", s.length);
printf("pointer: %lu\n", (unsigned long) s.data);

Result:

length:  140737488347584
pointer: 0

I want to avoid having to call an initialisation function on each new string just to set length to zero.

More information

Now that I think about it, it may not be really necessary to do this in my particular case (though it would be nice) because most people would initially set the string through ctou (which imports UTF-8 from char pointer) and that function sets length to zero anyway.

+4  A: 

You could use

string s = {0,NULL};
Shane MacLaughlin
Better, though it would be optimal if I could set an option in the struct definition to do this automatically. Declaring a new string like that every time probably won't be that nice for the developers who may use this library.
Delan Azabani
Automatically, that's using C++ and its constructors...
Nicolas Viennot
+1, but I'd modify your answer with s/could/should/.
Jens Gustedt
Heh, sed.­­­­­­
Delan Azabani
`{0}` would work better than `{0,NULL}`. The former works even if you change the implementation and order of members. The latter breaks if you change the struct.
R..
A: 
#define DEFINE_STRING(s) string s = {0, NULL}

{
    DEFINE_STRING(s);
}

You can use a macro to "do this automatically"

Nicolas Viennot
-1 for macro abuse that makes code gratuitously hard to read.
R..
@R: It's a very common idiom in the Linux kernel sources: [DEFINE_WAIT](http://lxr.linux.no/#linux+v2.6.35.5/include/linux/wait.h#L306), and you have DEFINE_LIST(), DEFINE_SPIN_LOCK(), ... pretty much all the primitives.
Nicolas Viennot
And when you are squeezing the last instruction out of the code in the kernel, such primitives are not gratuitous. In application code, they would be.
msw
Look at the libc...
Nicolas Viennot
+1  A: 

To combine the two previous answers (sort of) I'd define something like

#define STRING_INITIALIZER {0, NULL}
.
.
string s = STRING_INITIALIZER;

BTW, your struct declaration itself looks weird for a string. Either this is not a string as we usually understand it in C but merely a dynamic array of unsigned, or it is really a string and then this should be char*.

Jens Gustedt
It's a Unicode struct where all the 32-bit code points are stored in full in `data`.
Delan Azabani
@Delan: ah, I see. Then I'd either go for `wchar_t`, `uint32_t` or `uint_least32_t` according to your needs.
Jens Gustedt
Why? On both i386 and amd64, `int` is a 32-bit value. Also, I don't want `wchar_t` because that's a 16-bit value.
Delan Azabani
I just tested on i686 and x86_64 and for me `wchar_t` is 32 bit wide in both cases. Using another type than `unsigned` better shows your intent for it and explicits the tacit assumptions you have. But it is your code. May the gods of portability and amnesia bite you !-)
Jens Gustedt
You should be using `uint32_t` for Unicode code points, to make sure you don't make the type larger than it needs to be. And more importantly, you should use `size_t` rather than `unsigned long` for the length.
R..
@R.: good points. How come that I didn't notice the wrong type of length?
Jens Gustedt
+1  A: 

The accepted answer answered the question that you asked, but didn't address whether you ought.

Your string is a class and has class semantics. The initializer may be fine for kernel code where every last instruction counts, but in application code your static initializers are ugly and error prone.

It is possible to write classes in C, the stdio FILE type is a fabulous example, and here is the same idea applied to your string class:

typedef struct {
  int length;
  char *data;
} String;

String *sopen() {
  String *s = malloc(sizeof(String));
  if(s) {
    s->length = 0;
    s->data = NULL;
  }
  return s;
}

int sclose(String *s) {
  free(s->data);
  free(s);
  return 0;
}

int main()
{
   String *s = sopen();
   return sclose(s);
}

Where I've followed the FILE* function name style for metaphoric reasons. Yep, there's more code. Yep, you have to explicitly deallocate the structure; but note that even though you were counting on auto class initialization in your code sample, if data was ever allocated, you couldn't count on leaving scope to automatically deallocate the storage for you.

This approach also has the merit of abstracting the type of data from the users of the class. As there seems to be some confusion about what type you really want to use, this flexibility may come in handy.

msw