Avoiding repetition / loop unswitching - c

I have hotspot code which runs in a tight loop:
for (i = 0; i < big; i++)
{
if (condition1) {
do1();
} else if (condition2) {
do2();
} else {
do3();
}
// Shared code goes here
// More shared code goes here
}
Since condition1 and condition2 are invariant, I unswitched the loop to
if (condition1) {
for (i = 0; i < big; i++)
{
do1();
// Shared code goes here
// More shared code goes here
}
} else if (condition 2) {
for (i = 0; i < big; i++)
{
do2();
// Shared code goes here
// More shared code goes here
}
} else {
for (i = 0; i < big; i++)
{
do3();
// Shared code goes here
// More shared code goes here
}
}
This runs much better, but I wonder if there's a clever way to do this without repeating myself?

Another, possibly slightly more efficient option is to use a macro to construct the code for you:
#define DO_N(name, ...) for(int i = 0; i < big; i++){name(__VA_ARGS__);/*shared code*/}
if (condition1) {
DO_N(do1, .../*arguments here*/)
} else if (condition 2) {
DO_N(do2, ...)
} else {
DO_N(do3, ...)
}
#undef DO_N
Its ugly, but I think it does what you want, and might allow inlining where a function pointer does not.
Additionally, you may find it more readable to put your shared code in a separate macro or function.

I think you can declare a function pointer and some function foo():
typedef void (*fp)(void);
void foo(int big, fp f) {
for (int i = 0; i < big; ++i) {
f();
// Shared code goes here
// More shared code goes her
}
}
Then change your code for something like this:
if (condition1) {
foo(big, do1);
} else if (condition2) {
foo(big, do2);
} else {
foo(big, do3);
}

Related

Knuth Morris Pratt Algorithm, keep getting error "control reaches end of non-void function"

Code keeps returning the error "control reaches end of non-void function".
The source of the error is probably: int lps[M] but I can't figure out how to fix it. I tried to assign value to it but the error is still there.
EDIT: sorry about the return -1; thing. Fixed that but the error I'm trying to fix is still there.
int knuth(char *string, char * pattern){
int M = strlen(string);
int N = strlen(pattern);
int lps[M];
if (string == NULL)
{
return -1;
}
else {
int i = 0;
int j = 0;
while (i < N) {
if (string[j] == pattern[i]) {
j++;
i++;
}
if (j == M) {
//printf("Found stringtern at index %d ", i - j);
j = lps[j - 1];
return i - j;
} else if (i < N && string[j] != pattern[i]) {
if (j != 0)
j = lps[j - 1];
else
i = i + 1;
}
return i - j;
}
}
}
Ignoring all other potential problems in this function, the compiler is rightfully complaining that not all code paths return a value. You have declared the knuth function to return an int, yet it's possible for logic in your function to reach the end without returning a value. If you go down one of those paths, the function will return an indeterminate value, and if the caller uses that value, it will invoke undefined behavior. See the condensed version of your function below:
int knuth(char *string, char * pattern){
if (string == NULL)
{
return -1; // ok, here's a return, but it's conditional on string == NULL
}
else {
while (...) {
if (...) {
return i - j; // here's another return, also conditional
} else if (...) {
}
return i - j; // here's the final return in your function, which is
// conditional on entering the while loop
}
// what if you get here (ie, the condition of the while loop was false)?
// The function returns nothing, this is what the compiler is warning
// you about.
}
// Here is logically the same as at the end of the else block .. also no return
}
As I mentioned in my comment, there's no point to the while loop, since you unconditionally return from it at the end of the first iteration. That means the loop is guaranteed to only execute once, eliminating the need for a loop all together. Your logic can be simplified, at least with a method as below:
int knuth(char *string, char * pattern){
int i=0, j=0;
if (string == NULL)
{
return -1; // ok, here's a return, but it's conditional on string == NULL
}
else if (i < N) {
// if i < N, do whatever manipulations you want as before
if (...) {
// return i - j; // really no need to return i-j here, we'll do that
// at the end now
} else if (...) {
}
}
// now at the very end of the function, this will unconditionally return
return i - j;
}
However, I suspect you actually want to loop, in which case your logic should be something like
int knuth(char *string, char * pattern){
int i=0, j=0;
if (string == NULL)
{
return -1;
}
else
{
while (i < N)
{
// ... do your operations. Be _very_ careful to increment
// i appropriately (probably each time thru the loop), otherwise
// you'll get an infinite loop here. I see a conditional
// mutation of i in your OP, which makes me nervous.
}
// since this is the end of an else block, we can return here
//return i - j;
}
// but IMO it's clearer to return here. It's up to you, depending on
// where you want to scope i and j
return i - j;
}
Your code falls off the end of the function when string == NULL.
This writing style is old; typically we would not write
if(string != NULL)
{
/* Entire body logic */
}
but rather we would now write
if(string == NULL)
{
/* handle input error and return; or do we do string = ""; */
}
You will find this mistake more easily avoided by using the modern style. It has been pointed out to me that string can't be NULL here because of the strlen(string) call above. While such a platform does exist where strlen() checks for NULL, depending on that behavior is unwise, and the check should be moved before the strlen(string) call.
Nobody believes in single return anymore, which was the only real reason for the old style.

Tools to expand or inline sub-functions in C-code

Background:
Often I have to deal with C source code without any documentation during firmware development/maintenance. When the code deals with big data structures where the data members initialization scattered all over the place, it becomes very challenging to jump around different source and header files and often I got lost.
So my current solution is to spend several days to "flatten out" the code. I don't know what the appropriate term, but basically what I do is expanding the sub-functions and replacing the input parameters variable names with the actual variable names that passed into the sub-function. (Please see an oversimplified example below)
The outcome of this exercise is very helpful, but it is a very manual and tedious process. Since I'm doing firmware, on some chips that supports trace capability, it is possible to do this using JTAG debugger. But this set up is not always available.
I know with macros I can use the preprocessor to do this, but I couldn't figure out how to do it with sub-functions, if such a tool exists. I tried Googling 'subfunction expansion' etc., so far no luck. Please let me know if you know such a tool exists or the proper term(s) of what I'm trying to do so I can search it better on the Internet. Thanks a lot!
int myGlobal;
void increment(int input)
{
input++;
}
void decrement(int input)
{
input--;
}
int doSomething(int input, int op)
{
if (op)
{
increment(input);
}
else
{
decrement(input);
}
}
int main(void)
{
int i, currMax;
int myOp = 1;
myGlobal = 0;
currMax = 5;
for (i = 0; i < currMax; i++)
{
doSomething(myGlobal, myOp);
}
currMax = 4;
myOp = 0;
for (i = 0; i < currMax; i++)
{
doSomething(myGlobal, myOp);
}
}
BECOMES
int main(void)
{
int i, currMax;
int myOp = 1;
myGlobal = 0;
currMax = 5;
for (i = 0; i < currMax; i++)
{
// doSomething(myGlobal, myOp);
if (myOp)
{
// increment(myGlobal);
myGlobal++;
}
else
{
decrement(myGlobal);
myGlobal--;
}
}
currMax = 4;
myOp = 0;
for (i = 0; i < currMax; i++)
{
// doSomething(myGlobal, myOp);
if (myOp)
{
// increment(myGlobal);
myGlobal++;
}
else
{
// decrement(myGlobal);
myGlobal--;
}
}
}

Function Warnings in C

Hello guys i have threefunctions for which i get 4 warnings...!!
The first one is this
void evaluatearxikos(void)
{
int mem;
int i;
double x[NVARS+1];
FILE *controlpointsarxika;
controlpointsarxika = fopen("controlpointsarxika.txt","r");
remove("save.txt");
for(mem = 0; mem < POPSIZE; mem++)
{
for(i = 0; i < NVARS; i++)
{
x[i+1] = population[mem].gene[i];
}
rbsplinearxiki();
XfoilCall();
population[mem].fitness = FileRead();
remove("save.txt");
}
fclose(controlpointsarxika);
}
For this one the compiler warns me tha variable x is set but not used...!! But actually i am using the variable x...!!!
The second function is this one...
void elitist(void)
{
int i;
double best,worst;
int best_mem,worst_mem;
best = population[0].fitness;
worst = population[0].fitness;
for(i = 0; i < POPSIZE - 1; i++)
{
if(population[i].fitness > population[i+1].fitness)
{
if(population[i].fitness >= best)
{
best = population[i].fitness;
best_mem = i;
}
if(population[i+1].fitness <= worst)
{
worst = population[i+1].fitness;
worst_mem = i+1;
}
}
else
{
if(population[i].fitness <= worst)
{
worst = population[i].fitness;
worst_mem = i;
}
if(population[i+1].fitness >= best)
{
best = population[i+1].fitness;
best_mem = i+1;
}
}
}
if(best >= population[POPSIZE].fitness)
{
for(i = 0; i < NVARS; i++)
{
population[POPSIZE].gene[i] = population[best_mem].gene[i];
}
population[POPSIZE].fitness = population[best_mem].fitness;
}
else
{
for(i = 0; i < NVARS; i++)
{
population[worst_mem].gene[i] = population[POPSIZE].gene[i];
}
population[worst_mem].fitness = population[POPSIZE].fitness;
}
}
For this one i get two warnings that the variables worst_mem and best_mem may be used uninitialized in this function..!! But i initialize values to both of them..!!
And the third function is this...
void crossover(void)
{
int mem,one;
int first = 0;
double x;
for(mem =0; mem < POPSIZE; mem++)
{
x = rand()%1000/1000;
if(x < PXOVER)
{
first++;
if(first%2 == 0)
{
random_Xover(one,mem);
}
else
{
one = mem;
}
}
}
}
For which i get that the variable one may be used unitialized..!! But it is initialized..!
Can you please tell me what is wrong with these functions...??
Thank you in advance
In your first function, you set (assign) x, but you never read it, hence you are not using it... you're only wasting CPU cycles by writing to it. (Note also that because you index it as i+1 you write beyond the space you've allocated for it).
In the second function, your initializations to those variables are in conditional blocks. You can see that (perhaps? I didn't verify) in all conditions they are initialized but your compiler isn't that smart.
In your third function, it does appear that one could be refered to without having first been initialized.
First: You set x but do not use it. It's a local variable that gets set but it's dropped as soon as the function returns.
Second: There might be values that makes it so that your best_mem/worst_mem never gets set in your if/else, but you are using them later on. If they haven't been set, they contain garbage if not initialized.
Third: While it shouldn't happen that you try to use an uninitialized variable in your code, it still looks weird and compiler doesn't see that it won't happen first time.
When you get compiler warnings, treat is as you are doing something wrong or rather not recommended and that it could be done in a better way.
The x variable is only used on the left hand side (i.e. assigned a value). You are not using that value on the right hand side or pass it to a function.
It may be possible to get to the end of the loop for(i = 0; i < POPSIZE - 1; i++) without those variables given a value. Why not set them in the declaration.
The call to random_Xover(one,mem); could be called when one is not set. Change the line int mem,one; to int mem,one = <some value>;

Array Equality Check Method

I have a method to check whether two arrays are equal.
private bool CheckArray(int[] ilk_dizi, int[] son_dizi)
{
for (int i = 0; i < 5; i++)
{
if (ilk_dizi[i]==son_dizi[i])
{
if (i==4)
{
return true;
}
else
{
continue;
}
}
else
{
return false;
}
}
}
but i have a "not all code returs value" error. Any Ideas?
you have the possibility of a "no return"
Be wary when using continue, alot of times it is not really necessary.
Try optimising your code as follows
private bool CheckArray(int[] ilk_dizi, int[] son_dizi)
{
for (int i = 0; i < 5; i++)
{
if (ilk_dizi[i]!=son_dizi[i])
{
return false;
}
}
return true;
}
You have continue inside one of the else blocks - and static analizer cannot infer arrays passed in are 5 long and that i=4 will eventually be reached.
Imagine you passed two equal arrays size 2 each - then you will hit continue twice and exit the for loop - what will be returned then? Thus the warning.
Either put return true; at the end of method's body, or revise your algorithm.

How can I break out of two nested for loops in Objective-C?

I have two for loops nested like this:
for(...) {
for(...) {
}
}
I know that there is a break statement. But I am confused about if it breaks both loops or just the one in which it was called? I need to break both ones as soon as I see that it doesn't make sense to iterate more times over.
If using goto simplifies the code, then it would be appropriate.
for (;;)
{
for (;;)
{
break; /* breaks inner loop */
}
for (;;)
{
goto outer; /* breaks outer loop */
}
}
outer:;
break breaks out of one loop, but you can add a check to the outer loop which breaks when the inner breaks.
bool dobreak = false;
for ( ..; !dobreak && ..; .. ) {
for ( ... ) {
if (...) {
dobreak = true;
break;
}
}
}
The break statement only gets you out of the innermost loop. If you don't want the added overhead in code, memory and performance of a dedicated state variable, I recommend refactoring the code out into a function or method of its own, and using return to get out of all the loops:
void do_lots_of_work(void)
{
int i, j;
for(i=0; i<10 ; i++)
{
for(j=0;j< 10; j++)
{
..
..
if(disaster_struck())
return; /* Gets us out of the loops, and the function too. */
}
}
}
Other than the already mentioned flag variable or goto you could throw an Objective-C exception:
#try {
for() {
for() {
#throw ...
}
}
}
#catch{
...
}
Others have mentioned how you can set a flag or use a goto, but I'd recommend refactoring your code so that the inner loop is turned into a separate method. That method can then return some flag to indicate that the outer loop should break. If you name your methods appropriately, this is much more readable.
for (int i = 0; i < 10; i++) {
if (timeToStop(i)) break;
}
-(bool) timeToStop: (int) i {
for (int j = 0; j < 10; j++) {
if (somethingBadHappens) return true;
}
return false;
}
Pseudocode, not tested, but you get the idea.
The break statement will only break out of the loop in scope, which is the parent loop. If you want to break out of the second loop as well you could use a boolean variable which is in scope of both loops
bool isTerminated = false;
for (...)
{
if (!isTerminated)
{
for(...)
{
...
isTerminated = true;
break;
}
}
else
{
break;
}
}
Change top loop's counter before break
for(i=0; i<10 ; i++)
for(j=0;j< 10; j++){
..
..
i = 10;
break;
}
Probably the easiest way is to use a "flag" variable
for(i=0; i<10 && (done==false); i++)
for(j=0;j< 10; j++){
..
..
if(...){done=true; break;}
}
Another solution is to factor out the second loop in a function:
int i;
for(i=0; i<10 ; i++){
if !innerLoop(i) {
break;
}
}
bool innerLoop(int i)
int j;
for(j=0;j< 10; j++){
doSomthing(i,j);
if(endcondtion){
return false;
}
}
}
The break statement breaks out of the innermost loop. An additional test and break statement would be needed to break out of the outer loop.
If a break is executed from within a set of nested loops, only the innermost loop in which the break is executed is terminated. (Just like standard C)
Exactly like the last ones are, generally like this:
for(i=0;i<a;i++){
for(j=0;j<a;j++){
if(Something_goes_wrong){
i=a;
break;
}
}
}
Just for grins, how about changing this true/false check into a method and using return statements:
- (bool) checkTrueFalse: parameters{
for ( ...) {
for ( ... ) {
if (...) {
return true;
}
}
}
return false;
}

Resources