#define STRING(s) (((String*)s)-1)
what in the world is (((String*)s)-1)
?
typedef
struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
#define STRING(s) (((String*)s)-1)
what in the world is (((String*)s)-1)
?
typedef
struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
You're casting s
to a String *
. Then you're subtracting one from it (making it point to the previous whatever).
Anything more specific would need to know the definition of String
- but (WILD SPECULATION) I would guess the application uses dual VB/C-style strings (null terminated, preceded by the length), and this function changes it from a form suitable for C functions (pointer to the first character) into one usable for the other type (pointer to the length).
Don't know why the macro is made this way. Possibly the definition of String requires this, but that's just a wild guess.
Mechanically, the macro works as others have already described it. Semantically, though, you can think of this as a form of casting from char *
s to String *
s.
The String
structure is the header of a counted string, ie, one where you know the total length without having to scan for a NUL byte. This particular version also keeps the total allocated. You would create one as follows:
struct String *str = malloc(sizeof(*s) + maxlen);
str->length = 0;
str->capacity = maxlen;
str->checked = /* ??? */;
There should be some assorted functions around somewhere to manipulate these counted strings.
The macro itself is a hack to go from a plain char *
, assumed to point to the first character of the a String
as allocated above, back to a String *
. It would be used something like this:
/* allocate str as above */
char *s = str->p;
Now, through a chain of function calls or returns, you somehow loose track of the String structure containing s
, and you need to find it again. You write:
String *str2 = STRING(s);
This is not a particularly good way to implement a counted string in C, but it demonstrates a technique that one sees from time to time.
Others have answered your question. The technique of declaring ptr
inside struct String
with zero size is called "the struct hack", and wasn't portable until C99 (although it was widely used even before C99, and seems to work everywhere). The idea is that ptr
uses 0 bytes, so if you have a pointer to ptr
, and want one to the original struct, you would use the STRING
macro. You are subtracting the size of the struct
from the address of the ptr
member, and thus getting the start address of the struct
.
A better way to get the start address of a struct
given a pointer to any of its members is to use offsetof()
macro defined in stddef.h
. offsetof(struct type, member)
, as the name implies, gives the offset of member
in struct type
:
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
Then you can do:
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
typedef struct String {
int length;
int capacity;
unsigned check;
char ptr[0];
} String;
#define STRING(x) ((String *)(((char *)(x) - offsetof(struct String, ptr))))
int main(void)
{
String *s = malloc(sizeof *s + 100);
String *t;
char *mystring = s->ptr;
t = STRING(mystring);
assert(t == s);
return EXIT_SUCCESS;
}
offsetof()
is defined in stddef.h
.
Note that in C99, "struct hack" would declare ptr
inside the struct
as:
char ptr[];
i.e., without a size.