Delay Routine: Fully-portable C89 if possible

Well that's fine, although I am still having trouble imagining an actual example, from the perspective of my own work.

OK - although I know there are others advocating the exclusive use of these types.

--

John Devereux
Reply to
John Devereux
Loading thread data ...

That is a matter of personal taste.

Dunno, maybe, but it is not relevant.

No. Unless the C-standard has changed overnight this is not true.

per section 6.7.2 of the standard all of "long", "unsigned" and "int" are called 'type-specifier' in the standard. A list of valid _sets_ of type- specifiers is presented in that section and it includes "long" and "long int" as well "unsigned" and "unsigned int", etc. per section 6.7.3 'type-qualifier' is defined as one of "const", "restrict" or "volatile" and nothing else.

Rob

Reply to
rob windgassen

... snip ...

I disagree. "unsigned long" is guaranteed to have at least 32 bits. Similarly "unsigned int" is guaranteed at least 16 bits, as is "unsigned short". "unsigned char" is at least 8 bits. These types are ALWAYS available, but the various 'uint32_t' etc. types are not. Even if present, they are only present on a C99 compiler system. Why abandon portability unnecessarily?

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

... snip ...

Don't assume that gcc will check. It will if the format string is a known constant. It can't (in practice) if the format string is a variable. I.e.:

int doprint(char *s1, char *s2) { return printf(s1, s2); }

will do no checking.

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

That might be overkill for a simple delay timer. I don't like using a dummy loop for delays (too fiddly if noting else) but a simple poll on a free running timer should be sufficient for a delay.

Robert

--
Posted via a free Usenet account from http://www.teranews.com
Reply to
Robert Adsett

On the compiler that I use, CCS for PIC16, the default for an "unsigned int" is 8 bits while an "unsigned long" is 16 bits and an "unsigned short" is 1 bit. If you want 32 bits you have to use an "int32". All types are by default unsigned unless you explicitly declare them as signed.

Call it broken or non-compliant if you want, but it is what it is and it's been like that for several years and through many revisions of the complier.

I've also used gcc, C2C, Hi-tech, Avocet, and probably a few others on various platforms. Not all of them follow the rules.

I gave up this fight a long time ago. If the compiler that I'm using doesn't have then I just write my own. This way I'm guaranteed portability no matter what. I should mention that I tend to do a fair bit of development and testing on WIN32 and then just copy&paste the code as-is into the PIC compiler. Haven't encountered any portability problems yet.

--Tom.

Reply to
Tom

I've come a cropper using gcc for ARM by passing an integer to a sprintf that was expecting float. Caused my system to reset and took quite a long time to find.

Reply to
Tom Lucas

That's entirely correct. But in the few applications in which I use printf (or rather, snprintf), I use a fixed format string. If you are using a variable as the format string, then gcc can't help you with compile-time checks. gcc's format checking is not magical - but it's pretty good nonetheless. You can even misuse it as a way of type-checking other variable length parameter functions (if you feel such functions have any place in reliable programming).

mvh.,

David

Reply to
David Brown

I'm a great believer in the right tool for the job. If your programming is exclusively on 32-bit systems, then you can safely assume that "int" is 32-bit - that suits your code, and the work you are doing. For others, that may not be the case. Some people find that using "uint32_t" style types exclusively is best for *their* programming, while others like a mixture (size-specific for interfaces, "native" for things like minor local variables), and others like to use a range of application-specific types (such as one would with Ada). And in this particular thread, the O/P wanted safe portable code, which implies the need for size-specific types.

Reply to
David Brown

In the specific case of type names like "unsigned int", it is arguably a matter of taste - although it is a general rule of programming style that it is better to be explicit than implicit. "long", for example, can be used for both "long int" and "long double" - there is no type "long" in itself.

Other implicit "int" cases in C have been gradually dropped in newer standards. For example, it used to be legal to declare a function:

extern foo();

which returns an "int", and which takes as many "int" parameters as you want. This sort of thing is not a matter of taste - it is simply bad programming style, and contrary to every attempt at safe programming.

If the proposed newer C types _Fract and _Accum become a reality, then there will be an even stronger reason to drop the implicit "int", since these will also support specified types like "unsigned short _Fract".

On closer checking, it seems that the implicit "int" comes from the language "B", but the basic reason was to minimise keystrokes (that was also the reason for allowing functions without declarations, and other such implicit or abbreviated coding).

You are correct here regarding the official C terminology - "long", etc., are "type specifiers". But they do not in themselves form types - the "int" is implied if it is missing, but it is still part of the type.

Reply to
David Brown

As you say, an "unsigned long int" is guaranteed (by any strictly compliant compiler) to have *at least* 32 bits. But nowhere is it specified to have *at most* 32 bits. Thus "unsigned long int" is useless if I want *exactly* 32 bits. That is why the 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). When you are using compilers without , you need to write your own header with suitable typedefs - then you can keep your source code portable.

Reply to
David Brown

It's perhaps more accurate to talk about the platform "supporting"

32-bit integers - it's not clear whether you are trying to say that the cpu in question must be at least 32 bits (which is of course not the case - your code would work perfectly well on an 8-bit cpu, which regularly have 16-bit hardware registers and perhaps also 32-bit hardware registers) or just that it can work with 32-bit data (as distinct from, say, a 36-bit machine).

Reply to
David Brown

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.

Reply to
David Brown

The warnings will only work if enabled (-Wformat, or -Wall), and will depend somewhat on the library you are using (you probably need appropriate function attributes in the declaration of sprintf, although it's possible that gcc will add them automatically for standard *printf functions):

formatting link
formatting link

mvh.,

David

Reply to
David Brown

Does anyone have a public domain copy of stdint.h? Any number of people speak of rolling their own, but that seems a little silly if it's advocated that as many people as possible use stdint.h.

Reply to
Everett M. Greene

[...]

There is this one by Paul Hsieh .

It is not public domain, but seems to have a very permissive copyright.

--

John Devereux
Reply to
John Devereux

Impossible. The interface provided by 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 to exist. This header *has* to be either provided by the compiler writer, or tailored to a particular compiler by an informed programmer.

The point is that you should only roll your own if the compiler authors didn't provide on. But if you *are* going to roll your own, it's a good idea to roll your own along the lines of the standard version, rather than inventing yet another set of my_u32 types.

One of the problems this would avoid involves libraries from several independent vendors all used in the same project, who each thought they should roll their own type names for this, instead of following the C99 guidelines. The inevitable result is that two of them chose the *same* names, and now you get to resolve type redefinitions among other people's header files. Great fun --- not!

Reply to
Hans-Bernhard Bröker

I meant exactly what I wrote. The question is: does it _have_ a 32-bit data type, or not? The rules on uint32_t are quite clear: it's provided if and only if the platform has an unsigned integer type exactly 32 bits wide.

So if uint32_t isn't available, then there cannot possibly be 32-bit hardware registers for the up-thread code sample to use, because there's no type of the right width to work with them. Thus it should fail, and it'd preferrably fail as loudly as it can. I.e. it shouldn't even compile.

Reply to
Hans-Bernhard Bröker

While any hardware platform should be able to support uint32_t, the question is really how to support "volatile uint32_t" in all cases, since the C language specification does not specify how to handle interrupt disabling.

Paul

Reply to
Paul Keinanen

I thought that was what you meant, but was not entirely sure.

"volatile" has absolutely nothing to do with atomic access! This is not an uncommon mistake, but it is a misunderstanding that can lead to very subtle problems that are hard to diagnose (that's the case with most atomic access errors). C has no way to describe an atomic access - all "volatile" gives you is a promise to read from or write to the memory system when asked, and with restrictions on re-ordering. It says nothing about atomic access, and nothing about cache issues or memory writeback buffers (another common misconception about "volatile", relevant to bigger cpus).

Reply to
David Brown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.