For strict ANSI or C89 compilers you would get into some trouble though.. as soon as you add some other code before using loop(). That's because variables can't be declared after code. Something slightly hackish like this can work around it though:
#include <stdio.h>
static int _xyzxyx;
#define loop(x) for (_xyzxyx = 0; _xyzxyx < x; _xyzxyx++)
int main (void) {
int test = 0;
/*
* Add some code, this would trigger a problem with ANSI with the
* original version
*/
printf ("Starting here\n");
loop(5) {
printf ("%d it works...\n", ++test);
}
return (0);
}
But having that helper global variable isn't all nice, it would leave a bad taste in the mouth if you try to put the loop define in a header file, for example.
If all you want to use is GCC or modern C9x compilers then there aren't any problems, of course.
The cool thing is that it can still be done with other compilers...
#include <stdio.h>
#define loop(x) int i; for (i = 1; i <= x; i++)
int main(void) {
loop(5) {
printf("%i : it works...\n", i);
}
return(0);
}
I tested it with GCC & Ch on Linux. Somebody else would need to try it with Catalina or compiler of choice.
This works with Catalina ... but it is just a coincidence. You will see the problem if you put any executable statement before the "loop". For example:
#include <stdio.h>
#define loop(x) int i; for (i = 1; i <= x; i++)
int main(void) {
[COLOR=red]printf ("Starting...\n");[/COLOR]
loop (5) {
printf("%i : it works...\n", i);
}
return(0);
}
This will throw a compilation error on a C89 compiler. C89 requires an additional set of curly brackets around a declaration that appears in the middle of a statement block (in this case, the declaration "int i").
However, the following slight modification will work on any C compiler:
#include <stdio.h>
#define loop(x) [COLOR=red]{[/COLOR] int i; for (i = 1; i <= x; i++)
int main(void) {
printf ("Starting...\n");
loop (5) {
printf("%i : it works...\n", i);
}[COLOR=red]}[/COLOR]
return(0);
}
The ability to mix declarations and statements without requiring another curly bracket was one of the minor differences between C89 and C99 - but this is one that is quite useful, so many C compilers implement it. I may one day add it to Catalina (it has already been added to several other LCC-based compilers). However, it is not very high on my list of priorities, since all it really saves you is the cost of typing a another curly bracket.
Ross.
EDIT: I see Tor beat me to it - but I think my solution is better
EDIT: I see Tor beat me to it - but I think my solution is better
I thought of that one, but rejected it because it needs that extra '}' which makes the usage different from a proper language-defined loop(). It will also mess up auto-indentation in editors that support it (because it becomes unbalanced).
Here's another version for strict ANSI compilers.. it uses a function though.
#include <stdio.h>
static int loopf (int x) {
static int y;
if (y == 0)
y = x+1;
return (--y);
}
#define loop(x) while (loopf(x))
int main (void) {
int test = 0;
loop(5) {
printf ("%d it works...\n", ++test);
}
loop(4)
printf ("Hey\n");
return (0);
}
I thought of that one, but rejected it because it needs that extra '}' which makes the usage different from a proper language-defined loop(). It will also mess up auto-indentation in editors that support it (because it becomes unbalanced).
Here's another version for strict ANSI compilers.. it uses a function though.
...
Clever! I agree the extra } is a pain - but my solution supports nested loops, whereas yours does not (because of the static declaration).
Also, if you don't like }}, you can #define endloop }}
Yep. With MIPSPro C 2.1 (SGI, not the latest compiler) we get:
>cc -c loop.c
"loop.c", line 14: error(1241): declaration may not appear after executable
statement in block
int i;
^
1 error detected in the compilation of "loop.c".
And with IBM VisualAge C v5 we get:
"loop.c", line 14.5: 1506-275 (S) Unexpected text 'int' encountered.
"loop.c", line 14.9: 1506-045 (S) Undeclared identifier i.
Later versions of both compilers handle late-declared variables though, which certainly makes certain things easier (but can be abused as well, as is often the case when features are added).
You know, RavenKallen was about to suspend Propeller operations so as to dedicate time to learning C.
And now his thread has a long treatise on the use of C macros. Not only is this seriously over the top for a beginner in C the use of macros in this way, to create a loop construct for example, is seriously frowned upon in the C community.
You know, RavenKallen was about to suspend Propeller operations so as to dedicate time to learning C.
And now his thread has a long treatise on the use of C macros. Not only is this seriously over the top for a beginner in C the use of macros in this way,
True - it's fun to discuss such things, but it probably belongs in a different thread.
*
to create a loop construct for example, is seriously frowned upon in the C community.
Err yeah...and except for what I have done to create threads using an extension to GCC that allows void pointers to point to labels and then gotos the pointers.
Err yeah...and except for what I have done to create threads using an extension to GCC that allows void pointers to point to labels and then gotos the pointers.
Hey, computed gotos.. aka Fortran assigned gotos! Good old times!
"Since Fortran doesn't have a structured IF, REPEAT ... UNTIL, or CASE statement, Real Programmers don't have to worry about not using them. Besides, they can be simulated when necessary using assigned GOTOs."
-- from 'Real Programmers Don't Use Pascal', letter to Datamation magazine, July 1983)
Err yeah...and except for what I have done to create threads using an extension to GCC that allows void pointers to point to labels and then gotos the pointers.
Isn't C great? You can do literally anything. This is of course the great virtue of C, and the reason that after 30 years, it is still so popular as both an embedded language and as a systems programming language.
But the price you pay for this power and flexibility is complexity and (sometimes) portability.
To bring this back to the original reason for this thread (which was that Ravenkallen wanted to learn C), I think an important part of learning C is understanding this tradeoff.
If the prospect of the complexity of C scares you, then you probably shouldn't be learning it. If the prospect of the power of C excites you, then you probably should!
Comments
The cool thing is that it can still be done with other compilers...
I tested it with GCC & Ch on Linux. Somebody else would need to try it with Catalina or compiler of choice.
But having that helper global variable isn't all nice, it would leave a bad taste in the mouth if you try to put the loop define in a header file, for example.
If all you want to use is GCC or modern C9x compilers then there aren't any problems, of course.
-Tor
This works with Catalina ... but it is just a coincidence. You will see the problem if you put any executable statement before the "loop". For example:
This will throw a compilation error on a C89 compiler. C89 requires an additional set of curly brackets around a declaration that appears in the middle of a statement block (in this case, the declaration "int i").
However, the following slight modification will work on any C compiler:
The ability to mix declarations and statements without requiring another curly bracket was one of the minor differences between C89 and C99 - but this is one that is quite useful, so many C compilers implement it. I may one day add it to Catalina (it has already been added to several other LCC-based compilers). However, it is not very high on my list of priorities, since all it really saves you is the cost of typing a another curly bracket.
Ross.
EDIT: I see Tor beat me to it - but I think my solution is better
Here's another version for strict ANSI compilers.. it uses a function though.
Clever! I agree the extra } is a pain - but my solution supports nested loops, whereas yours does not (because of the static declaration).
Also, if you don't like }}, you can #define endloop }}
Ross.
-Tor
If I compile with... gcc -pedantic -std=c89 scratch.c -o scratch ...it fails with...
If I use clang/llvm ... clang -std=c89 scratch.c -o scratch ... compiles...
if I add -pedantic, this is the error it gives...
-Tor
And now his thread has a long treatise on the use of C macros. Not only is this seriously over the top for a beginner in C the use of macros in this way, to create a loop construct for example, is seriously frowned upon in the C community.
Appearantly not in this community
Ravenkallen is getting a taste of what he'll encounter with his new-found mastery of C
Maybe we could suggest peer reviews, at least to get feedback as to what is good practice and what might cause issues?
* Right, except for the 'do while (0)* trick :-)
-Tor
See "labels as values" here : http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
"Since Fortran doesn't have a structured IF, REPEAT ... UNTIL, or CASE statement, Real Programmers don't have to worry about not using them. Besides, they can be simulated when necessary using assigned GOTOs."
-- from 'Real Programmers Don't Use Pascal', letter to Datamation magazine, July 1983)
-Tor
Isn't C great? You can do literally anything. This is of course the great virtue of C, and the reason that after 30 years, it is still so popular as both an embedded language and as a systems programming language.
But the price you pay for this power and flexibility is complexity and (sometimes) portability.
To bring this back to the original reason for this thread (which was that Ravenkallen wanted to learn C), I think an important part of learning C is understanding this tradeoff.
If the prospect of the complexity of C scares you, then you probably shouldn't be learning it. If the prospect of the power of C excites you, then you probably should!
Ross.