Difficulties compiling typedefs (Resolved)

I'm having difficulties compiling in the 1.0 IDE. Most of the grief seems to have clustered around typedef statements. The most aggravating of the bunch was that I used

typedef unsigned long long time_t;

to save typing and improve readability. The compiler spewed out a ton of error messages and I ended up going back through all of the code and replacing the typedef name with the long form.

Well, it still didn't like

typedef void(*fptr_t)(void);

So I went through the code again doing the same as before, except this time the result was a lot less readable.

With that fixed, I could focus on the typedef'd structures (and the pointers to them). The compiler rejected

typedef struct event_d
{  struct event_d *next;
   unsigned long long when;
   void (*what)(void);
}  event;

but is perfectly happy with

typedef struct
{  unsigned long long t;               /* Date/time stamp                     */
   unsigned e;                         /* Radiation event count               */
   unsigned h;                         /* Temperature                         */
}  ring_t;                             /*  end: ring buffer element           */

and I'm completely baffled. Can anyone offer any insight as to what might be going on?

(all disclaimers apply :slight_smile:

check this on the function pointers and #typedef

The Function Pointer Tutorials - Syntax par 2.7
or
Function Pointers in C and C++ - Cprogramming.com

typedef struct
http://www.netalive.org/codersguild/posts/1753.shtml

I added this:

typedef unsigned long long time_t;
typedef void(*fptr_t)(void);
typedef struct event_d
{  struct event_d *next;
   unsigned long long when;
   void (*what)(void);
}  event;

to an existing sketch and it compiled (on V1.0) without complaint.
Maybe there's something else going on.

Pete

A typedef statement requires two parts - the new name and the part that the new name refers to.

typedef Junk struct junk;

says that Junk is equivalent to struct junk, and that either name can be used. So:

struct junk anInstance;

or

Junk anInstance;

(Presuming, of course that the struct is really defined somewhere.)

In

typedef unsigned long long time_t;

you have nothing but a collection of reserved words - no unique name for the type with a long name.

The compiler then thinks that you are trying to re-purpose unsigned. Clearly, you can not do that.

So, was something missing from that example?

@robtillaart - Thank you, but I understood all of that already. (I've been writing C since midyear 1980). Before trying to compile for the Arduino I test compiled the individual modules with gcc so as to avoid these kinds of problems. My query is about the Arduino compiler.

@el_supremo - I think there may be, but I can't put a finger on it. Was kinda hoping someone else had seen the problem and had found either an explanation or a work-around.

@PaulS - right (+/-). The name part goes where the identifier associated with the object would normally appear. Identifiers ending in '_t' are normally reserved for the compiler implementation, but that rule isn't generally enforced and, specifically, isn't enforced by gcc. I did try changing time_t to time_m (which isn't reserved) but the compiler bitched about that, too.

With the typedef names replaced by the actual type definitions, the compiler was happy - and the code has been chugging along on my little Mega 2560 without problems for about three hours now.

I think I'll try re-downloading the Arduino software and see if that brings any improvement. Thanks to all.

Can you reduce the problem to a small chunk of code and post that?

Pete

Pete...

Here's all of the original code from one of the modules:

typedef unsigned long long time_t;     /* Define a time_t data type           */
/*----------------------------------------------------------------------------*/
/* Define a translation unit scope variable to hold latest RESET time         */
/*----------------------------------------------------------------------------*/
static time_t rst_time = 0-0;          /* Epochal time of latest RESET (msec) */
/*----------------------------------------------------------------------------*/
/* Extend millis() for 64-bit up-time (TU scope only)                         */
/*----------------------------------------------------------------------------*/
static time_t ms64(void)
{  static union                        /* tl and ts[] occupy same location    */
   {  time_t tl;                       /* tl is 64-bit time in msec           */
      unsigned long ts[2];             /* ts[0] is bits 32-63, ts[1] is 0-31  */
   }  u = { 0 };                       /* initialize to count from RESET time */
   unsigned long t = millis();         /* 32-bit time from millis()           */
   if (t < u.ts[1]) ++u.ts[0];         /* If millis() has rolled over, adjust */
   u.ts[1] = t;                        /* Update with new millis() value      */
   return u.tl;                        /* Return 64-bit uptime                */
}                                      /*  end: ms64()                        */
/*----------------------------------------------------------------------------*/
/* Set RESET date/time using externally-supplied current epochal date/time    */
/*----------------------------------------------------------------------------*/
void set_time(time_t t)
{  rst_time = t - ms64();              /* Calculate RESET time                */
}                                      /*  end: set_time()                    */
/*----------------------------------------------------------------------------*/
/* Return current date/time as msec into the epoch                            */
/*----------------------------------------------------------------------------*/
time_t mst(void)
{  return rst_time + ms64();           /* Return reset time + uptime          */
}                                      /*  end: mst()                         */
/*----------------------------------------------------------------------------*/
/* time() - return current date/time as sec into the epoch                    */
/*----------------------------------------------------------------------------*/
time_t time(time_t *t)
{  time_t secs = mst() / 1000;         /* Drop milliseconds                   */
   if (t) *t = secs;                   /* If a pointer was supplied, use it   */
   return secs;                        /* Return system date/time in secs     */
}                                      /*  end: time()                        */

And here's what it became in order to satisfy my 1.0 IDE:

static unsigned long long rst_time = 0;/* Epochal time of latest RESET (msec) */
/*----------------------------------------------------------------------------*/
/* Extend millis() for 64-bit up-time (TU scope only)                         */
/*----------------------------------------------------------------------------*/
static unsigned long long ms64(void)
{  static union                        /* tl and ts[] occupy same location    */
   {  unsigned long long tl;           /* tl is 64-bit time in msec           */
      unsigned long ts[2];             /* ts[0] is bits 32-63, ts[1] is 0-31  */
   }  u = { 0 };                       /* initialize to count from RESET time */
   unsigned long t = millis();         /* 32-bit time from millis()           */
   if (t < u.ts[0]) ++u.ts[1];         /* If millis() has rolled over, adjust */
   u.ts[0] = t;                        /* Update with new millis() value      */
   return u.tl;                        /* Return 64-bit uptime                */
}                                      /*  end: ms64()                        */
/*----------------------------------------------------------------------------*/
/* Set RESET date/time using externally-supplied current epochal date/time    */
/*----------------------------------------------------------------------------*/
void set_time(unsigned long long t)
{  rst_time = t - ms64();              /* Calculate RESET time                */
}                                      /*  end: set_time()                    */
/*----------------------------------------------------------------------------*/
/* Return current date/time as msec into the epoch                            */
/*----------------------------------------------------------------------------*/
unsigned long long mst(void)
{  return rst_time + ms64();           /* Return reset time + uptime          */
}                                      /*  end: mst()                         */
/*----------------------------------------------------------------------------*/
/* time() - return current date/time as sec into the epoch                    */
/*----------------------------------------------------------------------------*/
unsigned long long time(unsigned long long *t)
{  unsigned long long secs = mst() / 1000; /* Drop milliseconds               */
   if (t) *t = secs;                   /* If a pointer was supplied, use it   */
   return secs;                        /* Return system date/time in secs     */
}                                      /*  end: time()                        */

Ah, the "ever helpfull"™ Arduino IDE in action!

typedef unsigned long   milli_seconds_t;

milli_seconds_t          msTarget;

//void funct(const milli_seconds_t& ms){}    // <-- uncomment to reproduce

As LloydDean notes, the IDE is making a mess of the sketch. For example, this code:

char junk;

typedef unsigned long long time_t;
static time_t rst_time = 0;

time_t ms64(void)
{
  static union {  
      time_t tl;
      unsigned long ts[2];
   }  u = { 0 };
   unsigned long t = millis();
   if (t < u.ts[1]) ++u.ts[0];
   u.ts[1] = t;
   return u.tl;
}

void setup()
{
}

void loop()
{
}

when compiled produces the intermediate .cpp output file:

#include "Arduino.h"
time_t ms64(void);
void setup();
void loop();
char junk;

typedef unsigned long long time_t;
static time_t rst_time = 0;

time_t ms64(void)
{
  static union {  
      time_t tl;
      unsigned long ts[2];
   }  u = { 0 };
   unsigned long t = millis();
   if (t < u.ts[1]) ++u.ts[0];
   u.ts[1] = t;
   return u.tl;
}

void setup()
{
}

void loop()
{
}

As you can see it has put the definitions of setup() and loop() at the front of the file. But it has also put the definition of ms64 in front of the typedef - which is why you get errors about 'time_t' does not name a type.
At the moment I haven't figured out a way to sidestep the "ehlp" from the IDE.

Pete

I got it to compile by putting the typedef into a .h file and then making the #include the first line in the source code file.

Pete

Thanks, Pete - I don't think I'd have figured it out on my own. I knew I was in trouble when the error messages appeared with .cpp, when (in my mind) they should have been .c :-/

I suppose I could have used a #define time_t unsigned long long to get around this problem, but that wouldn't have done much to solve the problem for structures. I was hoping that I'd done something patently stupid that could be easily repaired - but hopefully we'll see an Arduino 1.01 IDE before too long.

At least the executable is still running - that much is fun and exciting.

Once again my thanks to you and everyone who tried to help!

but hopefully we'll see an Arduino 1.01 IDE before too long.

I wouldn't count on it, and I wouldn't count on the IDE's behavior improving much. It has not changed in significant ways for quite a while.

I've been away from serious code for "a long time". That's > 10 years, coming on 15 so please bear with me.

When I see
typedef unsigned long long time_t;

I get sort of the willies cause it just looks wrong to me, I don't know know what it's trying to do. It looks like code doubletalk.

I can understand
typedef unsigned long time_t;

Although the name time_t ... looks like something I'd expect the system already uses but if it doesn't then sure, name it!

But what's the point of "unsigned long long" as opposed to "unsigned long" here?
As you can see, the IDE isn't the only one confused!

unsigned long long is a perfectly valid type. Unusual, yes, but still valid. It defines a 64 bit unsigned value.

"long long" is a bigger type than "long." Really, "long" is just a shorthand for "long int," too (although I think in the latest language rev, it's now a real type on its own.)
What i was wondering in this whole thread was what the errors given actually were. The fact that the compiler throws an error is one thing. WHAT that error is is a lot more helpful.
For example, if you try to typedef time_t, when <time.h> has already gotten included somehow, that'll generate one kind of error, which may be different from some other kinds of errors (like missing semicolons :slight_smile:

Arduino can handle 64-bit integers, signed and unsigned?!?

I needs a Tex Avery jaw drop smiley! Scuse me while I wander around all goofball for a while.....

@GoForSmoke - An (unsigned) long on the Arduino is 32-bits, and an (unsigned) long long is 64-bits. A 32-bit millisecond timer will wrap every 49.7 days - and a 64-bit millisecond timer will wrap approximately every 5 gazillion years. I don't need that much, but I know/hope I'm going to need more than 49 days - so I'll pay the price.

If I included <time.h>, then I'd suck in a definition of time_t - but since I want to ensure 64-bits, I'm not including it. This means I have to provide my own time functions, but that isn't a problem. You aren't as confused as you think you are. :slight_smile:

@jwatte - el_supremo identified the source of the errors: the IDE was, effectively, re-ordering source code in such a way as to force errors where there had been none coded. If I weren't so suave and debonaire, I'd probably be REALLY PISSED OFF - but I'm not. 8)

@GoForSmoke - ROFL! Yes, but "handle" doesn't necessarily mean Arduino has 64-bit registers or instructions. :grin:

The only way the wrap should be a problem is if you're watching for durations longer than 49.71... days.

How about time64_t for clarity as well as uniqueness?

Hmmm, I know the ATmega is 8 bit.. by handle I mean actually able to do calculations with, shift, etc.

I have a box in a closet with my late 70's TI programmable calculators, a TI-56 and a TI-59 on print cradle. I believe they're 4-bit machines capable of 20-digit precision, probably using BCD in microcode. Back in 1977 I used the 56 to run the map table while in a US Army radar crew. Months later the Sound-Flash guys all had green TI-56's. I think that by 81 the expected upgrades obsoleted the lot.

I could, but I've got a heap of ready-to-use POSIX code that I'm too lazy to change. What I did (between exchanges here) was:

#define time_t unsigned long long      /* Define a 64-bit time type           */
#define fptr_t(x) void(*x)()           /* Define a function pointer type      */

which isn't pretty, but takes care of a lot of the non-structure problems. The structure headache came from trying to use the structure tag within the structure typedef. I solved that problem (which shouldn't have been a problem) by coding an "incomplete declaration" and then using the now-known tag in my typedef. Sounds more complicated than it actually is:

struct evnt_d                          /* Define a queue element's structure  */
{  struct evnt_d *next;                /*   Pointer to next element           */
   time_t when;                        /*   Scheduled execution time (msec)   */
   fptr_t(what);                       /*   Pointer to callback routine       */
};                                     /* End event structure definition      */
typedef struct evnt_d evnt_t;          /* Define typedef for event structure  */

Which the compiler allowed.