I am a newbie to microcontroller C programming and I am running into a few problems with using nested loops.
Following is a sample construct that I have in my C code. The problems are mentioned subsequently
// I am trying to ramp down the while loop
while (i>= stop_value)
{
step_value = default_value;
R32(a particular register, content_register);
if (content_register = a_set_value)
{
if( step_value <= step_max)
{
step_value = step_value +1;
i=start_value;
continue;
}
if(step_value =step_max)
{
// do something;
break;
}
}
WR32(a particular register, content_reset_register); // resetting the register
i=i-1;
}
Basically, I am trying to do the following:
ramp down a loop till it reaches the stop_value and also read a particular register while ramping down.
If the register has a defined value, then check if the step_value<= step_max. If step_value < step_max then reset the while loop by using continue statement, and setting i to initial start value. At this point of time, my step_value should be the latest value and not the default step value. I do understand that above code is not completely correct for step_value because I initialize step_value to default_value.( So, how do I modify the initial step_value = default_value statement so that first time when the loop executes, I have a default_value and subsequently the most recent step_value?)
But, if step_value equals my step_max then just do something and break subsequently( this part works!). Also, when I use the continue statement, I should reset the contents of the register.
So, I want to effectively reset the while loop with the latest step_value, contents of the register reset when my step_value is less than step_max? Thank you for your replies!
In this code:
if( step_value <= step_max)
{
step_value = step_value +1;
i=start_value;
continue;
}
if(step_value =step_max)
{
// do something;
break;
}
The second if cannot ever be reached. You are checking <= and then skipping to the bottom of the loop with continue.
From your above logic:
then check if the step_value<= step_max. If step_value < step_max then reset the while loop by using continue statement, and setting i to initial start value.
That code should probably read:
if( step_value < step_max)
{
step_value = step_value +1;
i=start_value;
continue;
}
...
Then the second if could be evaluated. This should be generating compiler warnings like crazy about unreachable code and assignment within if statements. Please turn on your compiler warnings and listen to them!
I assume that at least one of the following alternatives apply:
First, in C language = is an assigment which returns the value assigned and assumes true if that value is not equal to 0.
So you have to use == in all if statements instead of = (unless it is desired behaviour that you assign and check for != 0 in the if statement in one step - but even in that case I'd prefer to do this in 2 steps for better maintainability), i.e. instead of
if (content_register = a_set_value)
{
// your code
}
I would say
content_register = a_set_value;
if (content_register!=0)
{
// your code
}
to make it more clear what you're checking against.
Second, if step_value==step_max (and you're properly using == in the 2nd if) then both IFs are executed, which is not what you want. So you I assume you meant < instead of <=.
Third, from our chat I got the information from you that the loop is waiting for a register change coming from an external thread. In this case the loop is simply too fast resetting the register. Consider synchronization or at least add a thread sleep after resetting the register to allow the other thread to change the register.
Change this and see if it works.
Related
I'm writing a timer/scheduler simple program for Arduino.
It's a c program, with 'main' loop that is running again and again.
Arduino has DS3231 RTC module connected to it and provides the current day-of-week, hour, minute, second, etc.
What I need to achieve is sending a specific string over the serial port, but in contrast to many examples about 'lighting a LED at a specific time' - I can't allow the code to run more than once.
So, if a normal 'light a LED on a specific time' just loops again and again the 'if' check and according to it sets the digital output 'HIGH' or 'LOW' (again and again) - I can't use this approach.
The approach I'm using now, and it works, is like this:
I made an array with the wanted times, and 'action code' for each time - all of them are Integers, like this:
const int A = 6; // Action Array Size
int ActionTimes[A][4] = {
{6,18,37,1},
{6,18,38,2},
{5,15,20,11},
{5,16,35,51},
{5,16,40,52},
{5,23,55,15}
};
Then, from the main loop I call a "Check" function that runs a 'for' loop to check if there is an action that should be run in this current time:
int i;
for ( i = 0; i < A; i++ ) {
if ((dt.DayOfWeek()==ActionTimes[i][0]) && (dt.Hour()==ActionTimes[i][1]) && (dt.Minute()==ActionTimes[i][2]) && (dt.Second() < 2)) {
RunMyAction(ActionTimes[i][3]);
}
And then - I have the 'action' function that runs the actual needed code, like this:
void RunMyAction(const int& MyActionCode)
{
switch(MyActionCode) {
case 1:
digitalWrite(2, LOW); // Turn the LED on by making the voltage LOW
Serial.println("S041ONE");
break;
case 2:
digitalWrite(2, HIGH); // Turn the LED off by making the voltage HIGH
Serial.println("S017ONE");
break;
case 11: //Before Knissat Shabat - Full status update.
Serial.println("S01D00000D00ES02D01001100ES03D00101101ES04D1100D0DDES05D10011DDDE");
delay(1000);
break;
case 15: //Last GoodNight Shabat - Full status update.
Serial.println("S01D00000000ES02D00000000ES03D00000100ES04D1000D00DES05D00011DDDE");
delay(1500);
break;
case 51:
Serial.println("S036OFE");
delay(1500);
break;
case 52:
Serial.println("S047OFES036ONE");
delay(1500);
break;
}
}
That works for me and 'do the job' but I feel (algorithmically speaking) maybe it's not the best way to write it.
For example - all the actions and the needed times are hard-coded into the program itself. For any added action - I have to manually change the const of the array size, manually change the array definition, and add additional code to the switch function.
(Thought about excel-made #include files to merge into the array part and the switch function, but this also has to re-compile the program for every time/action change).
Would appreciate any insight about how to look at it for more professional, effective, way.
Many thanks!
To avoid executing the same action twice in a row, I'd add a global variable to hold the index into ActionTImes[] of the most recently executed action, then test that variable in the if statement.
int latestActionIndex = -1; // -1 so on startup we don't think we've executed ActionTimes[0].
then in the For loop:
if ((dt.DayOfWeek()==ActionTimes[i][0])
&& (dt.Hour()==ActionTimes[i][1])
&& (dt.Minute()==ActionTimes[i][2]
&& latestActionIndex != i)) {
latestActionIndex = i; // note that we've run this action
RunMyAction(ActionTimes[i][3]);
}
I removed the (dt.Second() < 2) from the if statement, because the action will likely execute within a second or so of dt.second() == 0, and the new variable keeps RunMyAction() from being executed more than once.
Our organization has a required coding rule (without any explanation) that:
if … else if constructs should be terminated with an else clause
Example 1:
if ( x < 0 )
{
x = 0;
} /* else not needed */
Example 2:
if ( x < 0 )
{
x = 0;
}
else if ( y < 0 )
{
x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
/* no change in value of x */
}
What edge case is this designed to handle?
What also concerns me about the reason is that Example 1 does not need an else but Example 2 does. If the reason is re-usability and extensibility, I think else should be used in both cases.
As mentioned in another answer, this is from the MISRA-C coding guidelines. The purpose is defensive programming, a concept which is often used in mission-critical programming.
That is, every if - else if must end with an else, and every switch must end with a default.
There are two reasons for this:
Self-documenting code. If you write an else but leave it empty it means: "I have definitely considered the scenario when neither if nor else if are true".
Not writing an else there means: "either I considered the scenario where neither if nor else if are true, or I completely forgot to consider it and there's potentially a fat bug right here in my code".
Stop runaway code. In mission-critical software, you need to write robust programs that account even for the highly unlikely. So you could see code like
if (mybool == TRUE)
{
}
else if (mybool == FALSE)
{
}
else
{
// handle error
}
This code will be completely alien to PC programmers and computer scientists, but it makes perfect sense in mission-critical software, because it catches the case where the "mybool" has gone corrupt, for whatever reason.
Historically, you would fear corruption of the RAM memory because of EMI/noise. This is not much of an issue today. Far more likely, memory corruption occurs because of bugs elsewhere in the code: pointers to wrong locations, array-out-of-bounds bugs, stack overflow, runaway code etc.
So most of the time, code like this comes back to slap yourself in the face when you have written bugs during the implementation stage. Meaning it could also be used as a debug technique: the program you are writing tells you when you have written bugs.
EDIT
Regarding why else is not needed after every single if:
An if-else or if-else if-else completely covers all possible values that a variable can have. But a plain if statement is not necessarily there to cover all possible values, it has a much broader usage. Most often you just wish to check a certain condition and if it is not met, then do nothing. Then it is simply not meaningful to write defensive programming to cover the else case.
Plus it would clutter up the code completely if you wrote an empty else after each and every if.
MISRA-C:2012 15.7 gives no rationale why else is not needed, it just states:
Note: a final else statement is not required for a simple if
statement.
Your company followed MISRA coding guidance. There are a few versions of these guidelines that contain this rule, but from MISRA-C:2004†:
Rule 14.10 (required): All if … else if constructs shall be terminated
with an else clause.
This rule applies whenever an if statement is followed by one or more
else if statements; the final else if shall be followed by an else
statement. In the case of a simple if statement then the else
statement need not be included. The requirement for a final else
statement is defensive programming. The else statement shall either
take appropriate action or contain a suitable comment as to why no
action is taken. This is consistent with the requirement to have a
final default clause in a switch statement. For example this code
is a simple if statement:
if ( x < 0 )
{
log_error(3);
x = 0;
} /* else not needed */
whereas the following code demonstrates an if, else if construct
if ( x < 0 )
{
log_error(3);
x = 0;
}
else if ( y < 0 )
{
x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
/* no change in value of x */
}
In MISRA-C:2012, which supersedes the 2004 version and is the current recommendation for new projects, the same rule exists but is numbered 15.7.
Example 1:
in a single if statement programmer may need to check n number of conditions and performs single operation.
if(condition_1 || condition_2 || ... condition_n)
{
//operation_1
}
In a regular usage performing a operation is not needed all the time when if is used.
Example 2:
Here programmer checks n number of conditions and performing multiple operations. In regular usage if..else if is like switch you may need to perform a operation like default. So usage else is needed as per misra standard
if(condition_1 || condition_2 || ... condition_n)
{
//operation_1
}
else if(condition_1 || condition_2 || ... condition_n)
{
//operation_2
}
....
else
{
//default cause
}
† Current and past versions of these publications are available for purchase via the MISRA webstore (via).
This is the equivalent of requiring a default case in every switch.
This extra else will Decrease code coverage of your program.
In my experience with porting linux kernel , or android code to different platform many time we do something wrong and in logcat we see some error like
if ( x < 0 )
{
x = 0;
}
else if ( y < 0 )
{
x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
/* no change in value of x */
printk(" \n [function or module name]: this should never happen \n");
/* It is always good to mention function/module name with the
logs. If you end up with "this should never happen" message
and the same message is used in many places in the software
it will be hard to track/debug.
*/
}
Only a brief explanation, since I did this all about 5 years ago.
There is (with most languages) no syntactic requirement to include "null" else statement (and unnecessary {..}), and in "simple little programs" there is no need. But real programmers don't write "simple little programs", and, just as importantly, they don't write programs that will be used once and then discarded.
When one write an if/else:
if(something)
doSomething;
else
doSomethingElse;
it all seems simple and one hardly sees even the point of adding {..}.
But some day, a few months from now, some other programmer (you would never make such a mistake!) will need to "enhance" the program and will add a statement.
if(something)
doSomething;
else
doSomethingIForgot;
doSomethingElse;
Suddenly doSomethingElse kinda forgets that it's supposed to be in the else leg.
So you're a good little programmer and you always use {..}. But you write:
if(something) {
if(anotherThing) {
doSomething;
}
}
All's well and good until that new kid makes a midnight modification:
if(something) {
if(!notMyThing) {
if(anotherThing) {
doSomething;
}
else {
dontDoAnything; // Because it's not my thing.
}}
}
Yes, it's improperly formatted, but so is half the code in the project, and the "auto formatter" gets bollixed up by all the #ifdef statements. And, of course, the real code is far more complicated than this toy example.
Unfortunately (or not), I've been out of this sort of thing for a few years now, so I don't have a fresh "real" example in mind -- the above is (obviously) contrived and a bit hokey.
This, is done to make the code more readable, for later references and to make it clear, to a later reviewer, that the remaining cases handled by the last else, are do nothing cases, so that they are not overlooked somehow at first sight.
This is a good programming practice, which makes code reusable and extend-able.
I would like to add to – and partly contradict – the previous answers. While it is certainly common to use if-else if in a switch-like manner that should cover the full range of thinkable values for an expression, it is by no means guaranteed that any range of possible conditions is fully covered. The same can be said about the switch construct itself, hence the requirement to use a default clause, which catches all remaining values and can, if not otherwise required anyway, be used as an assertion safeguard.
The question itself features a good counter-example: The second condition does not relate to x at all (which is the reason why I often prefer the more flexible if-based variant over the switch-based variant). From the example it is obvious that if condition A is met, x should be set to a certain value. Should A not be met, then condition B is tested. If it is met, then x should receive another value. If neither A nor B are met, then x should remain unchanged.
Here we can see that an empty else branch should be used to comment on the programmer's intention for the reader.
On the other hand, I cannot see why there must be an else clause especially for the latest and innermost if statement. In C, there is no such thing as an 'else if'. There is only if and else. Instead, the construct should formally be indented this way (and I should have put the opening curly braces on their own lines, but I don't like that):
if (A) {
// do something
}
else {
if (B) {
// do something else (no pun intended)
}
else {
// don't do anything here
}
}
Should any standard happen to require curly braces around every branch, then it would contradict itself if it mentioned "if ... else if constructs" at the same time.
Anyone can imagine the ugliness of deeply nested if else trees, see here on a side note. Now imagine that this construct can be arbitrarily extended anywhere. Then asking for an else clause in the end, but not anywhere else, becomes absurd.
if (A) {
if (B) {
// do something
}
// you could to something here
}
else {
// or here
if (B) { // or C?
// do something else (no pun intended)
}
else {
// don't do anything here, if you don't want to
}
// what if I wanted to do something here? I need brackets for that.
}
In the end, it comes down for them to defining precisely what is meant with an "if ... else if construct"
The basic reason is probably code coverage and the implicit else: how will the code behave if the condition is not true? For genuine testing, you need some way to see that you have tested with the condition false. If every test case you have goes through the if clause, your code could have problems in the real world because of a condition that you did not test.
However, some conditions may properly be like Example 1, like on a tax return: "If the result is less than 0, enter 0." You still need to have a test where the condition is false.
Logically any test implies two branches. What do you do if it is true, and what do you do if it is false.
For those cases where either branch has no functionality, it is reasonable to add a comment about why it doesn't need to have functionality.
This may be of benefit for the next maintenance programmer to come along. They should not have to search too far to decide if the code is correct. You can kind of Prehunt the Elephant.
Personally, it helps me as it forces me to look at the else case, and evaluate it. It may be an impossible condition, in which case i may throw an exception as the contract is violated. It may be benign, in which case a comment may be enough.
Your mileage may vary.
Most the time when you just have a single if statement, it's probably one of reasons such as:
Function guard checks
Initialization option
Optional processing branch
Example
void print (char * text)
{
if (text == null) return; // guard check
printf(text);
}
But when you do if .. else if, it's probably one of reasons such as:
Dynamic switch-case
Processing fork
Handling a processing parameter
And in case your if .. else if covers all possibilities, in that case your last if (...) is not needed, you can just remove it, because at that point the only possible values are the ones covered by that condition.
Example
int absolute_value (int n)
{
if (n == 0)
{
return 0;
}
else if (n > 0)
{
return n;
}
else /* if (n < 0) */ // redundant check
{
return (n * (-1));
}
}
And in most of these reasons, it's possible something doesn't fit into any of the categories in your if .. else if, thus the need to handle them in a final else clause, handling can be done through business-level procedure, user notification, internal error mechanism, ..etc.
Example
#DEFINE SQRT_TWO 1.41421356237309504880
#DEFINE SQRT_THREE 1.73205080756887729352
#DEFINE SQRT_FIVE 2.23606797749978969641
double square_root (int n)
{
if (n > 5) return sqrt((double)n);
else if (n == 5) return SQRT_FIVE;
else if (n == 4) return 2.0;
else if (n == 3) return SQRT_THREE;
else if (n == 2) return SQRT_TWO;
else if (n == 1) return 1.0;
else if (n == 0) return 0.0;
else return sqrt(-1); // error handling
}
This final else clause is quite similar to few other things in languages such as Java and C++, such as:
default case in a switch statement
catch(...) that comes after all specific catch blocks
finally in a try-catch clause
Our software was not mission critical, yet we also decided to use this rule because of defensive programming.
We added a throw exception to the theoretically unreachable code (switch + if-else). And it saved us many times as the software failed fast e.g. when a new type has been added and we forgot to change one-or-two if-else or switch. As a bonus it made super easy to find the issue.
Well, my example involves undefined behavior, but sometimes some people try to be fancy and fails hard, take a look:
int a = 0;
bool b = true;
uint8_t* bPtr = (uint8_t*)&b;
*bPtr = 0xCC;
if(b == true)
{
a += 3;
}
else if(b == false)
{
a += 5;
}
else
{
exit(3);
}
You probably would never expect to have bool which is not true nor false, however it may happen. Personally I believe this is problem caused by person who decides to do something fancy, but additional else statement can prevent any further issues.
I'm currently working with PHP. Creating a registration form and a login form. I am just purely using if and else. No else if or anything that is unnecessary.
If user clicks submits button -> it goes to the next if statement... if username is less than than 'X' amount of characters then alert. If successful then check password length and so on.
No need for extra code such as an else if that could dismiss reliability for server load time to check all the extra code.
As this question on boolean if/else if was closed as a duplicate. As well, there are many bad answers here as it relates to safety-critical.
For a boolean, there are only two cases. In the boolean instance, following the MISRA recommendation blindly maybe bad. The code,
if ( x == FALSE ) {
// Normal action
} else if (x == TRUE ) {
// Fail safe
}
Should just be refactored to,
if ( x == FALSE ) {
// Normal action
} else {
// Fail safe
}
Adding another else increases cyclometric complexity and makes it far harder to test all branches. Some code maybe 'safety related'; Ie, not a direct control function that can cause an unsafe event. In this code, it is often better to have full testability without instrumentation.
For truly safety functional code, it might make sense to separate the cases to detect a fault in this code and have it reported. Although I think logging 'x' on the failure would handle both. For the other cases, it will make the system harder to test and could result in lower availability depending on what the second 'error handling' action is (see other answers where exit() is called).
For non-booleans, there may be ranges that are nonsensical. Ie, they maybe some analog variable going to a DAC. In these cases, the if(x > 2) a; else if(x < -2) b; else c; makes sense for cases where deadband should not have been sent, etc. However, these type of cases do not exist for a boolean.
I am trying to search through an array, and only check specific values (the 4th,5th and so on)- ((0+n*4) and (3+n*4).
The first one found will be checked and if it has a value of 0 will it be changed to 1 and then the program should stop. If not it will try the next value and so on..
I have the following code, but it doesn't stop ..it makes all the values 1 at once..
Any suggestions?
{
for (i=0; i<(totalnumber); i++)
{ for (n=0; n<((totalnumber)/4); n++)
{ if (i==(0+(n*4)))
{ if (array[i]==0)
{
array[i]=1;
break;
}
}
else if ((i==(3+(n*4))))
{
if (array[i]==0)
{
array[i]=1;
break;
}
}
}
}
}
Using a single break statement only breaks out of the nearest loop. It doesnt break out of the outer i loop. So, change your code to break out of the outer loop too.
One other way is to use both counter variables i,n within the same for loop. That means, you only use break once to break out of the outer for loop.
I quote from MSDN
Within nested statements, the break statement terminates only the do, for, switch, or while statement that immediately encloses it. You can use a return or goto statement to transfer control elsewhere out of the nested structure.
This is related - Can I use break to exit multiple nested for loops?
First this gets triggered:
if ((temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) | (temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit))
activateAlarm(channelID);
Activate alarm is triggered, then from there:
void activateAlarm(int channelID);
{ while (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit || temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit)
{
logSubsystem(temperatureChannel[channelID].currentTemperature);
}
}
Then alarm screen is triggered with following case:
int logSubsystem(int currentTemperature)
case 'F': //if user input is 'F'
case 'f': //if user input is 'f'
currentTemperature--;
printf("your current exceeded temp is %i\n \n", currentTemperature);
if (currentTemperature <= 100 || currentTemperature >= 50);
compareLimit();
break; //exits loop
How do I set up this function so that if the user decrements with F and gets the current temperature to below the limit (<100, or >50), then it will return back to the compareLimit function and the requirement for the high limit/low limit triggered state will be FALSE, returning the program to its original pre-alarm state?
I think you would benefit considerably from thinking a lot about how your program flows. Right now, what I can deduce of your program flow is:
You have an outer loop that checks the temperature, on at least one channel ID. Inside that loop, you have the if statement you first showed us.
Then activate alarm does some other stuff, but loops until the temperature goes down, calling logSubsystem.
logSubsystem then presumably gets some kind of user input, and from there, you want it to call to your initial function, presumably called prepare limit.
The problem with this is that none of these functions ever complete. They all call each other, and you'll eventually get a stack overflow. Nice, since that's the name of this site, but not something you want to aspire to.
What you basically need is a state machine. You need something that keeps track of values, looks at those values, and calls functions that return that operate on those values. There should only be one loop, and it should do all the control of what happens based on what those values are. The good news is, you have all of this in place already. temperatureChannel is keeping track of the values for you, and you have while loops a-plenty.
Let me give you my suggestion of the way I suggest your program should flow:
bool checkTemperatureValuesOutOfRange(int channelID) {
// this is just a convenience, to make the state machine flow easier.
return (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) || // note the || not just one |
(temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit);
}
void actOnUserInput() {
char input = // ... something that gets a user input. It should check if any is available, otherwise return.
switch (input) {
case 'F':
case 'f':
temperatureChannel[channelID].currentTemperature--;
break; // This doesn't exit the loop - it gets you out of the switch statement
}
void activateAlarm(int channelID) {
// presumably this does something other than call logSubsystem?
// if that's all it does, just call it directly
// note - no loop here
logSubsystem(channelID);
}
void logSubsystem(int channelID) { // Not the current temperature - that's a local value, and you want to set the observed value
// I really think actOnUserInput should be (an early) part of the while loop below.
// It's just another input for the state machine, but I'll leave it here per your design
// Presumably actually logs things, too, otherwise it's an unnecessary function
actOnUserInput();
}
while (TRUE) { // this is the main loop of your function, and shouldn't exit unless the program does
// do anything else you need to - check other stuff
// maybe have a for loop going through different channelIDs?
if (checkTemperatureValuesOutOfRange(channelID)) {
activateAlarm(channelId);
// do anything else you need to
}
I'm sure you can see lots of differences between your code and mine. Here are some key things to consider:
All the functions now return. The master while loop calls functions that check status, and calls function that change status.
I would highly suggest acting on the user input as part of the master while loop. It's just another input to the state machine. Get it, act on it, and then check your statuses. You presumably need to have some input from the user, otherwise you'll never get in a bad state in the first place.
Right now, activate alarm happens every time. With the code you showed, that's fine - because logSubsystem was all that was being called. If you only want the alarm to ring once, keep a boolean tracker inside temperatureChannel[channelId] that says if the alarm rang, set it true within activateAlarm, and then reset it to false based on the return value of checkTemperatureValuesOutOfRange.
Rather than leaving yourself in the activateAlarm/logSubsystem area, you return each time, and check your values each time to see if you're still there. This is the key point - your functions should be fast, and not monopolize your processor. Make each function do just one sort of thing, and have all the control come from within the master loop.
I made a lot of changes to your code, and I don't know if you're allowed to make all of them, but you'll need something similar to this. It's much more robust, and gives you room to grow all around.
I am confused by the for(;;) construct. I think it is a form of shorthand for an unlimited for loop but I can't be sure.
Here is the code:
for(;;)
{
//whatever statements
}
Your guess is correct; it's an infinite loop.* This is a common C idiom, although many people (including me) believe the following to be less cryptic:
while (1) { whatever statements; }
* It's infinite assuming there are no break/return/etc. statements inside the loop body.
It's an un-terminated loop. It is sometimes written with a while:
while (1)
or even better:
while (true)
I would expect to see a break or return inside any such loop, no matter whether it is written with for or while. There has to be some abnormal control flow or it really will be an infinite loop.
Yes, that's the for C syntax with blank fields for initialization expression, loop condition and increment expression.
The for statement can also use more than one value, like this sample :
for (i=0, j=100, k=1000; j < 500 || i<50 || k==5000; i++, j+=2, k*=6) {};
Maybe one step beyond in for understanding ? =)
Yes, the expressions in the for loop are just optional. if you omit them, you will get an infinite loop. The way to get out is break or exit or so.
This statement is basically equal to:
while(1) {}
There is no start, no condition and no step statement.
As I understand it, for(;;) creates a deliberate non-exiting loop. Your code is expected to exit the loop based on one or more conditions. It was once provided to me as a purer way to have a do while false loop, which was not considered good syntax. Based on the exit condition, it is easier to dispatch to a function to handle the result, failure, warning, or success, for example.
My explanation may not be the reason someone used that construct, but I'll explain in greater detail what it means to me. This construct may be someone's "Pure C" way of having a loop in which you can serially perform multiple steps, whose completion mean something like your application has performed all steps of initialization.
#define GEN_FAILURE -99
#define SUCCESS 0
/* perform_init_step1() and perform_init_step2() are dummy
place-holder functions that provide a complete example.
You could at least have one of them return non-zero
for testing. */
int perform_init_step1();
int perform_init_step2();
int perform_init_step1()
{
return 0;
}
int perform_init_step2()
{
return 0;
}
int ret_code = GEN_FAILURE;
for(;;)
{
if(SUCCESS != perform_init_step1())
{
ret_code = -1;
break;
}
if(SUCCESS != perform_init_step2())
{
ret_code = -2;
break;
}
break;
}
If part of the initialization fails, the loop bails out with a specific error code.
I arrived at using C having done a lot of firmware work, writing in assembly language. Good assembly language programmers taught me to have a single entry point and single exit. I took their advice to heart, because their creed helped them and me immensely when debugging.
Personally, I never liked the for(;;) construct, because you can have an infinite loop if you forget to break; out at the end.
Someone I worked with came up with do..until(FALSE), but the amount of proper C furvor this caused was not to be believed.
#define GEN_FAILURE -99
#define SUCCESS 0
/* perform_init_step1() and perform_init_step2() are dummy
place-holder functions that provide a complete example.
You could at least have one of them return non-zero
for testing. */
int perform_init_step1();
int perform_init_step2();
int perform_init_step1()
{
return 0;
}
int perform_init_step2()
{
return 0;
}
int ret_code = GEN_FAILURE;
do
{
if(SUCCESS != perform_init_step1())
{
ret_code = -1;
break;
}
if(SUCCESS != perform_init_step2())
{
ret_code = -2;
break;
}
}
until (FALSE);
This runs once, no matter what.