Re: Polymorphism in C (very basic)

From: Jason Curl (j.curl_at_motorola.com)
Date: 07/09/04


Date: Fri, 9 Jul 2004 17:39:26 +0200

Thanks Arthur,

When I mentioned "Black Box", it wasn't quite exactly. Rephrasing, I think
logger might be better.

GPS data comes in once per second. In the background are various
measurements. There are about 60 measurements in total. An enum defines the
different measurements. In an OO implementation it might be an object that
has 60 properties, accessed by index. There are another 60 properties
associated with the measurements to indicated "Aged" or not.

Every time a GPS update arrives, an event is fired. Other processes get
notified. They can access one of the properties.

So,

#define CP_FLOAT32_UINT32(f32) (*((Uint32 *)(&(f32))))
#define CP_UINT32_FLOAT32(u32) (*((Float32 *)(&(u32))))

typedef enum {
    PROPERTY1,
    PROPERTY2,
    ....
    PROPERTY_GPSALT,
    PROPERTY_GPSSPEED,
    NUM_PROPERTIES
} Properties;

typedef struct {
    Uint32 Data[NUM_PROPERTIES];
    Bool Aged[NUM_PROPERTIES];
} Block;

Block foo;

->Initialisation: (this is why I asked the question).
CP_UINT32_FLOAT32(foo.Data[PROPERTY_GPSALT]) = 0.0;

-> In the background data arrives from another thread (all the mutex's are
not here). Maybe from multiple threads.
foo.Data[PROPERTYn] = value1;
foo.Aged[PROPERTYn] = FALSE;

->When GPS data arrives (I'm using regular expressions to parse the data)
float altitude;
altitude = (float)atof(matchv[1]);
foo.Data[PROPERTY_GPSALT] = CP_FLOAT32_UINT32(altitude);
(void)NotifyGpsEvent();

-> Then other modules (configured at compile time, to turn on or off
features) would get the event. One of these modules would write it to Flash
memory.

At the moment it's a concept, and I'm trying to figure out the best way. See
also my other comments embedded. I suspect that's pretty much it. Any more
would be deviating from C?

"Arthur J. O'Dwyer" <ajo@nospam.andrew.cmu.edu> wrote in message
news:Pine.LNX.4.58-035.0407090918160.2023@unix45.andrew.cmu.edu...
>
> On Fri, 9 Jul 2004, Jason Curl wrote:
> >
> > But for all your curiosity, why am I doing this? I've used C for quite
some
> > time and mostly on embedded systems. This is a kind of flight recorder,
> > where the data being recorded may change, but the number of data
elements to
> > record is fixed.
>
> And by "data elements" you mean... objects (i.e., more or fewer bytes
> of data depending on object size)? Bytes of data (i.e., more or fewer
> chunks of data depending on chunk size)? Something else?

Yes, objects that may be of variable sizes, but generally simple objects
(except the string). Each object is not more than 32-bits.

>
> > The array of Uint32's allows me to define a block of memory that is
> > allocated at compile time. The index to the array provides a very fast
way
> > to access that index.
>
> Oh, stop saying that already! Usenet posts aren't funding proposals;
> there's no need to pretend that Obvious Method #1 is a "very fast way"
> to do Trivial Thing #7. Besides, from the clc standpoint, nothing is
> necessarily "very fast" --- how do *we* know what kind of code your
> compiler generates? (And more to the point, how do *you* know what kind
> of code *our* compilers generate?)

Thanks for the input. Would it be wrong to assume how compilers access
elements in an array? Maybe I wasn't clear in how that array is being used.
I align the datatypes on 32-bit boundaries so that it is simple and fast to
access the elements. But enough of that topic. I understand there are other
ways I haven't thought of that might be as efficient, simpler and quicker.

>
> More usefully, I would strongly recommend the use of an array of
> 'unsigned char' rather than 'unsigned int'. It's a more direct tip-off
> to the maintainer that you're doing evil things with bits and bytes.
> Also, 'sizeof (unsigned char)' is always exactly 1, which will help you
> immensely in getting an accurate size for your buffer.
>
> > So it means I don't use "malloc" on initialisation. It also means in 80%
of
> > the cases I don't need to do type conversions of this sort because the
> > datatypes are already in some integer form.
>
> Type conversions are source-level constructs, generally speaking.
> In your case, they certainly don't add any code to the executable. So
> it's just a readability concern --- and IMHO you ought to be using a
> few cleverly-designed macros for readability and consistency anyway.
>
> > Hence, the point of the title, some basic
> > form of polymorphism in C.
>
> Nothing to do with polymorphism. Trust me. :) But it sounds an
> awful lot like "serialization"; you might Google up some references
> on that topic, if you have the time to spare. (Probably won't help
> you code it, but probably will give you a better idea of what you're
> probably *trying* to code.)

You're right. I just wanted an array where the datatypes are not all the
same. It's serialization.

>
> > I didn't want to have a solution using a Union construct, as when
> > initialising this array it means I first need to write to a temporary
> > variable and then copy that either using memcpy, union structs, or
> > typecasts. I simply wanted the compiler to take a float, without type
> > promotion or demotion and store it. Why not have one ASM instruction,
than
> > have three?
>
> Use gcc, which is very smart about memcpy and friends. (Possibly
> other common compilers are smart too, but I recently had cause to
> play with gcc's memcpy-vs-for-loop optimization in this newsgroup. ;)
> IOW, don't worry about efficiency. Cf. "First Rule of Optimization."
>
> > And the comment about the last part? Well..... Now you might know how I
> > intend to use the data and what it's for.
>
> If it's not too long, try posting an example of how you intend to
> *use* the subroutines you're writing. For example:
>
> BlackBox_clear();
> BlackBox_addF(3.14159);
> BlackBox_addI(6);
> BlackBox_addS("times");
> BlackBox_addI(9);
> BlackBox_addI(42);
> BlackBox_dump();
>
> If this is what you're looking at, then you might write the functions
> as follows [COMPLETELY UNTESTED CODE]:
>
> static unsigned char BB_buffer[1000];
> static size_t BB_idx = 0;
> static char BB_types[1000];
> static size_t BB_tdx = 0;
>
> void BlackBox_clear(void)
> { BB_idx = BB_tdx = 0; }
>
> #define BlackBox_add(c, t) \
> void BlackBox_add##c(t value) { \
> memcpy(BB_buffer+BB_idx, &value, sizeof value); \
> BB_idx += sizeof value; \
> BB_types[BB_tdx++] = #c [0]; \
> }
>
> BlackBox_add(I, int)
> BlackBox_add(F, float)
> #undef BlackBox_add
>
> void BlackBox_addS(const char *value) {
> size_t n = strlen(value)+1;
> memcpy(BB_buffer+BB_idx, value, n);
> BB_idx += n;
> BB_types[BB_tdx++] = 'S';
> }
>
> void BlackBox_dump(void)
> {
> int i, j=0;
> for (i=0; i < BB_tdx; ++i) {
> switch(BB_types[i]) {
> case 'I': {
> int value; memcpy(&value, BB_buffer+j, sizeof value);
> printf("int, value %d\n", value);
> j += sizeof value;
> }
> case 'F': {
> float value; memcpy(&value, BB_buffer+j, sizeof
value);
> printf("int, value %g\n", value);
> j += sizeof value;
> }
> case 'S': {
> printf("string, value '%s'\n", BB_buffer+j);
> j = strchr(BB_buffer+j, '\0')-BB_buffer + 1;
> }
> }
> }
> }
>
>
> ... A long example, but I think you get the idea.
>
> HTH,
> -Arthur



Relevant Pages

  • Re: Copying an array slice (Was: Re: Difficulties with passing multi-dimensional arrays)
    ... > the pointer to array of unknown size. ... but it still compiles without a cast. ... unknown at compile time so nothing can be checked. ...
    (comp.lang.c)
  • Re: Use of getchar
    ... "Cam" wrote in message ... I do this by calling a KeyboardInput() function ... > key2 array as if the user had entered them. ... compileable code, i.e., compile it yourself and then copy and paste it ...
    (comp.lang.cpp)
  • Re: A taxonomy of types
    ... array semantics, ...) ... you mean "following correct offset operator semantics"... ... What does exist is based exclusively on pointer type. ... they can't be compiled if the compiler does not know how to compile them, ...
    (comp.lang.misc)
  • Re: modifying array access syntax
    ... I published recent speculation on the ARRAY ... > are in fact remnants of the property lists of these Lisp-N ... these that were meaningful at compile time (FEXPR, FSUBR, and MACRO ...
    (comp.lang.lisp)
  • Calling LabVIEW DLL from C with 2d array strings
    ... I wanted to use the 2D array of strings since ... this would give a uniform interface for returning measurements. ... snippet from the header file generated when building the LabVIEW DLL: ...
    (comp.lang.labview)