Path: utzoo!utgpu!attcan!uunet!seismo!sundc!pitstop!sun!decwrl!megatest!djones From: djones@megatest.UUCP (Dave Jones) Newsgroups: comp.lang.c Subject: Re: Variable-length messages. Message-ID: <924@goofy.megatest.UUCP> Date: 23 Oct 88 01:24:49 GMT References: <2707@hound.UUCP> Organization: Megatest Corporation, San Jose, Ca Lines: 97 #define SLM 1 /* silly little macro */ Shall we define a message packet as follows? struct msg { int size; enum msg_type type; char contents[SLM]; }; Or with a header? struct hdr { int size; enum msg_type type; }; And then we package the contents separately? It is quite likely that I would choose neither. It depends partly on whether the solution is to be tuned for one program, and thus can have "direct knowledge" of the data-types being transmitted, or whether it is to be a general "library" solution. Is it supposed to transfer messages between machines of different types or between programs compiled with different compilers? (Apparently not.) Approximately how many different message types will there be? Will they differ significantly in size? Will they all have a fixed-size format? Etc.. But we still have the question as to whether or not the first declaration is even feasible. So, for now, let's go along with the gag, and look at the first declaration. How does one malloc such a thing, and how do you write bytes into it? What you've got to watch out for is alignment restrictions and conventions, and "holes" in structures. Some of the "solutions" which have been posted so far, and which purport to solve the problem don't. To begin with, the compiler may not align that one-char-array on a boundary suitable for just any kind of data. So lets back off and try again. /* The following is supposed to have the most general ** alignment of all types. */ typedef union { void* ptr; char c; short s; int i; long l; float f; double d; }max_align; struct msg { int size; enum msg_type type; max_align contents[1]; }; Now the "contents" field should be aligned on a boundary suitable for any data-type. (Did I miss something?) Now, I think the following will always work; But remember, I didn't recommend this approach, anyway. extern int errno; extern int pipe_out; int send(size, type, contents) int size; void* contents; enum msg_type type; { int packet_size = /* header overhead (including any padding or "holes") */ sizeof(struct msg) - sizeof(max_align) /* and add to that... */ + size; struct msg* msg; if((msg = (struct msg*)malloc(packet_size)) == 0) return errno; /* Fill out the header. */ msg->size = size; msg->type = type; /* Copy the message. */ bcopy(contents, (void*)(msg->contents), size); { int written = write(pipe_out, (void*)msg, packet_size); free(msg); return (written == packet_size)?0: errno; } }