-2

A C-coded S-function in Simulink was showing incorrect behaviour and I have managed to narrow down the problem to an incorrect multiplication of integers.

At the start of the code, I have something like:

#define NRBF       21
#define NRBF1  NRBF+1

Then, in a function in the script I have:

void function_name(SimStruct *S, const int_T a)
{
...
    int_T base;
    base = a*NRBF1;
    printf("%i\t", a);
    printf("%i\t", NRBF1);
    printf("%i\n", base);
..
}

Now, if a=0, NRBF=21, I have (instead of base=0)

0  22  1

If a=1, NRBF=21, I have (as expected base=22)

1  22  22

If a=2, NRBF=21, I have (instead of base=44)

2  22  43 

Now, I must say I am a bit baffled. I tried to change the line of the multiplication to

base = a* (int_T)NRBF1;

but it does not solve the problem.

Any help would be greatly appreciated! Thank you!

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
Enrico Anderlini
  • 447
  • 6
  • 21

4 Answers4

5

The problem is here:

You define your macros like this:

#define NRBF       21
#define NRBF1  NRBF+1

When you write this:

base = a*NRBF1;

The preprocessor replaces NRBF1 textually with 21+1 which results in this:

base = a*21+1;

but you intended this:

base = a*(21+1);

Therefore you need to define your macro like this:

#define NRBF1  (NRBF+1)
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
3

With the macro expanded, the line looks like:

base = a*NRBF+1;
  • For a equal to 0, the expression is 0 * 21 + 1 which is 1.
  • For a equal to 2, the expression is 2 * 21 + 1 which is 43.

The solution is to put parentheses in the macro definition:

#define NRBF1 (NRBF + 1)

This is a good rule for any macro with an expression as its right-hand side.

Remember that macros are just text-substituted into the code.

unwind
  • 391,730
  • 64
  • 469
  • 606
2

It's basically calculating alright

0*21+1 = 1

The macro is expanded but the * has precedence over +. That's why this happens.

A more detail explanation would be

#define NRBF       21
#define NRBF1  NRBF+1

So what is going on

base = a*NRBF1;

or

base = a*NRBF+1

Now when a = 0 then base = 1
    when a = 1 then base = 21+1 ...so on.

Correct way would be to wrap it aropund parentheses.

#define NRBF1  (NRBF+1)

Some more pitfalls:

That when you add a macro like this #define SQR(X) X*X

For some example like this where same precedence operators are there next to next then it will be problematic.

int i = 100/SQR(10);

Then it will be expanded to

int i = 100/10*10

Now same precedence operators are here executed left to right.

So it will result in i=100.

Solution same #define SQR(X) (X*X)

Also when passing an expression like this SQR(i+1) then it will be expanded to i+1*i+1=2*i+1. So a bit more correct would be

#define SQR(X) ((X)*(X))

Even with that you wouldn't be able to avoid few things if you forget one thing macro just expands - it does nothing more.

You can't use macro like this

SQR(i++) which will be expanded to ((i++)*(i++)). So you are increasing the i twice which is what you didn't mean. Moreover this will result in undefined behavior.

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • with `SQR(X) (X*X)` or even `SQR(X) ((X)*(X))` the problem is a little trickier, since `X` can be a side-effect expression or a function, and calling it twice may give unexpected results. – Jean-François Fabre Nov 22 '17 at 08:49
  • @Jean-FrançoisFabre.: Yes that's why I am writing and putting it in a later edit otherwise it will be interpreted wrong way – user2736738 Nov 22 '17 at 08:50
  • looks very much like there: https://stackoverflow.com/questions/3719150/square-of-a-number-being-defined-using-define – Jean-François Fabre Nov 22 '17 at 08:50
  • @Jean-FrançoisFabre.: I am writing. Yes it is problem when `SQR(i++)` that is expanded twice. – user2736738 Nov 22 '17 at 08:51
1

the define doesn't create a single value 22 but the expression 21 + 1. I wonder whether your problems go away if you change your second #define to #define NBRF1 (NBRF + 1)