capl

Declaring a variable inside a CAPL function leads to undefined behavior


Consider the following example:

main.can

includes {
  #include "sub.cin"
}

variables {
  msTimer tim;
  int number;
}

on start {
  setTimerCyclic(tim,20,20);
}

on timer tim {
  number = computeCRC8();
}

sub.cin

byte computeCRC8(byte input[], int nBytes)
{
    byte data;
    byte remainder = 0xAB;
    int B = 0;
    for (B = 0; B < nBytes; ++B)
    {
        data = input[B] ^ (remainder);
        remainder = some_LUT_included_elsewhere[data] ^ (remainder << 8);
    }
    return ( (remainder) ^ 0xAB );
}

This code compiles. some_LUT_included_elsewhere is actually defined in a proper manner.

This code returns random values at each execution.

If any instruction, e.g. write("hello world"); is inserted in computeCRC8 before variable definition, the code won't compile.

If variables are declared globally in a variables{} section instead, the code will compile and produce consistent results.

I've checked and made sure that no aliases for the variables exist in the code nowhere.

This behavior is confusing me. Is the compilation in the first place a bug in the Vector CAPL compilation toolchain? I shouldn't be able to declare variables inside a function, but I am, and the result is apparently randomized.


Solution

  • Regarding compilation error

    As far as I know, CAPL (which is C based) requires variables declaration before any instructions. There is nothing unusual about raising compilation error if you declare a variable after an instruction in any code block.

    Regarding inconsistent results

    All variables defined in CAPL are static. Which mean the value is initialized only once and on each function call it is carried from the previous function call.

    Problem in you code

    in file sub.cin

    byte computeCRC8(byte input[], int nBytes)
    {
        byte data;
        byte remainder;
        int B = 0;  // you initialize this value only once for program, not each function call like you intended
    
        reminder = 0xAB;  // set the value at the beginning of each function call
    
        for (B = 0; B < nBytes; ++B)  // B is set to 0 here so the previously set value does not matter
        {
            data = input[B] ^ (remainder);
            remainder = some_LUT_included_elsewhere[data] ^ (remainder << 8);
        }
        return ( (remainder) ^ 0xAB );
    }