EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Delay Routine: Fully-portable C89 if possible

Started by Martin Wells October 9, 2007
Paul Keinanen wrote:

> While any hardware platform should be able to support uint32_t,
Strange you should say that --- the experts on the C standard working group clearly thought otherwise. Or why else do you think they wrote all that stuff about the exact-width integer types all being optional?
> the question is really how to support "volatile uint32_t" in all > cases,
That's not actually a separate issue. A C implementor is not at liberty to provide uint32_t, but forbid qualifying it as volatile. I.e. if they want to shy away from volatile uint32_t, they can't offer uint32_t at all.
> since the C language specification does not specify how to handle > interrupt disabling.
Volatile has just about nothing to do with that. You're looking for (an improved version of) sigatomic_t.
Hans-Bernhard:

> It would be rather nice if a VALUE_BITS like that were a C89 standard > functionality, wouldn't it? Well, sorry, it's not. And not only that: > it can't even be implemented in C89. There's only CHAR_BIT (in > <limits.h>), and sizeof() --- but the latter doesn't work in > preprocessor instructions.
#define VALUE_BITS(m) (((m)-1) /(((m)-1)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \ + ((m)-1)%0x3fffffffL /(((m)-1)%31+1)/31%31*5 + 4-12/(((m)-1)%31+3)) Works for all unsigned integer types. Martin
David:

> *All* C standards are implemented to varying degrees, and *all* embedded > compilers add their own extensions. Take advantage of what you get > (such as <stdint.h>, inline, and // comments), and leave out the parts > that are poorly or inconsistently implemented (such as variable length-co > arrays). Even nominally C89 compilers frequently support such features.
There's nothing at all wrong with extra features, so long as they don't alter the behaviour of fully-standard-compliant programs or prevent them from compiling successfully.
> First the simple part - omitting the "int" part of declarations and > definitions is an abomination brought about by the terrible keyboards > K&R had to work with when developing C. The type in question is called > "long unsigned int" - "long" and "unsigned" are type qualifiers. The > language standards say that if a type is expected, but you haven't given > one, then an "int" is assumed, and any C compiler will accept that. But > the compiler will accept all sorts of hideous code and generate working > results - you have to impose a certain quality of code standards if you > are going to write good code. One of these rules is that if you mean a > type should be "int" (optionally qualified), then you write "int". If > you don't want to write out "long unsigned int", then use a typedef.
I do indeed write my code to a quality standard, and that standard finds nothing wrong with "unsigned". The majority of good C programmers leave out the redundant keywords unless they really wanna be explicit about what they're doing. When was the last time you saw "auto" in a C file? Or even in the real world, who writes a plus sign behind positive numbers?
> Secondly, I was suggesting that if you want portable code, you have to > use size-specific integer types.
Nope definitely not, you just have to be guaranteed to have a given range with the type. For example: short unsigned : at least through 65535 long : at least -2147483647 through 2147483647
> Using <stdint.h> is an easy way to get > that - otherwise, a common format header file that is adapted for the > compiler/target in question is a useful method. It doesn't really > matter whether you use "uint32_t" from <stdint.h>, or have a "typedef > unsigned long int uint32_t" in a common header file - nor does it matter > if you give the type your own name. But it *does* matter that you have > such types available in your code.
Again I contest the need for this.
> Certainly many of the situations where size specifics are important are > in hardware dependant and non-portable - and thus the only issue is that > the code in question is clear.
The microcontroller I'm using currently has 6-Bit ports but 8-Bit registers and memory chunks... still no problem though. Martin
Ulf:

> char's are sometimes set to unsigned char on small micros, > and to be able to guarantee signedness regardless of > compiler options is an improvement.
Plain char's should be used to store characters, so their sign is irrelevant. If you want to use a byte for arithmetic, then try signed char or unsigned char. Martin
David:

> That is why the <stdint.h> types > were defined, and that is why they are important if you want portable > code that works on a wide range of targets (at least, for architectures > that can support 8, 16 and 32-bit data - targets with 36 bit cpus, for > example, will always be problematic for portable code).
For what purposes would you want an integer type of a given size (other than an integer type of *at least* a given size)? The only difference between a 33-Bit int and a 32-Bit int is that the former will take longer to wrap around to zero upon overflow, and it will also retain an extra bit when left-shifted. You'll still have all the range you want though. Martin
David:

> When writing programs, it's important that they are understandable and > make sense when read. Thus the type "char" makes sense for holding a > character, or as part of a string - it does not make sense for holding a > number, for example. The types "unsigned char" and "signed char" do not > make any sense at all, and thus should only appear hidden away in a > header - typedef'ed names such as "uint8_t" and "sint8_t" make vastly > more sense.
With time you come to ignore the English-language meaning of the keywords. When's the last time you thought about the meaning of "static" when you wanted a private function, or a variable that stays around for the next function call. Martin
Hans-Bernhard:

> Impossible. The interface provided by <stdint.h> is standardized --- > but it's actual content isn't, and can't be. > > If portable code could define uint32_t itself, there would be no point > for <stdint.h> to exist. This header *has* to be either provided by the > compiler writer, or tailored to a particular compiler by an informed > programmer.
That's a very defeatist attitude... you'd be suprised what you can get done with a few macros. Martin
On Sat, 13 Oct 2007 00:33:08 -0700, Martin Wells <warint@eircom.net>
wrote:

><snip> >When was the last time you saw "auto" in a C file? ><snip>
I hate to tell you this, but I use it, religiously. Speeds my reading in cases where I am skimming though code and, also, the compiler will certainly complain if for some reason the line is placed outside a function, whether because a #define was used where it shouldn't have been or some cut and paste, etc. Doesn't cost me much, as I type at about 100 words a minute and I don't happen to mentally frame up code nearly as fast as I can type it. (I also use LET in BASIC, too, rather than just write the assignment itself. A habit I formed about three decades ago when writing a pretty-printer, after writing an interpreter for BASIC.) But I also think it is fine to leave them out. What is important is to be consistent in writing your application, so that others who are reading it can learn what to expect and then expect to see what they have learned from reading your code. Jon
On 2007-10-13, Martin Wells <warint@eircom.net> wrote:
> David: > >> That is why the <stdint.h> types >> were defined, and that is why they are important if you want portable >> code that works on a wide range of targets (at least, for architectures >> that can support 8, 16 and 32-bit data - targets with 36 bit cpus, for >> example, will always be problematic for portable code). > > > For what purposes would you want an integer type of a given > size (other than an integer type of *at least* a given size)?
When you want perform modulo-N arithmetic. -- Grant Edwards grante Yow! I had a lease on an at OEDIPUS COMPLEX back in visi.com '81...
Grant:

> > For what purposes would you want an integer type of a given > > size (other than an integer type of *at least* a given size)? > > When you want perform modulo-N arithmetic.
You can be fully portable and efficient at the same time. Unchecked, likely to contain an error or two: #define N 32 #if VALUE_BITS(char unsigned) == N # define MODULO_ARITHMETIC_N(a,b) ((char unsigned)((a) + (b))) #elif VALUE_BITS(short unsigned) == N # define MODUL... #else # define TWO_POW(x) (1 << (x)) - 1 | (1 << (x)) # define MODULO_ARITHMETIC_N(a,b) ((a) + (b) % TWO_POW((N))) #endif Martin

The 2024 Embedded Online Conference