Variables and constants

Names

Variable names can be of any length. The first character must be a letter or an underline "_". The name is case sensitive.

Note that a variable name in a control script (within a panel or a library function that is used in a panel) may not be the same as the used shape name.

Note that uses is a keyword used to include CTRL libraries into a CTRL code and may not be used as a variable name.

Default values

Each variable in Control has a default value even before the variable is initialized. The default value for numeric variables (int, float, double,...) is a value of 0 and the default for characters (char, string) is an empty string ("").

Manager-global variables

Manager-global variables created byaddGlobal(), are valid in all Scrips of the manager. The manager-global variables are initialized directly when you start the manager (declaration in Library).

Variable declaration after a statement

Variables can also be declared after a statement , for example, after a DebugN().

Example

main()
{
  exampl1();
}
void exampl1()
{
  int i = 0;
  DebugN("i is ",i);
  int s;
// New variable declaration after DebugN() statement
  s = i;
  DebugN("s gets the value of i", s);
}

Char constants, numeric constants

  • A char constant is a single character enclosed in single quotes, for example, 'x'.
  • Numeric constants consist of a string of digits. They are of type int (if they have no decimal point - otherwise they are of type float), and are normally interpreted as decimal numbers.
  • If the string begins with the digit 0 (zero), it is interpreted as an octal number, i.e. in base 8. This means that only the digits 0 - 7 are used for displaying a number. Using 8 and 9 results in a syntax error.
  • If the string begins with the combination 0x or 0X (digit 0, letter x), it is interpreted as a hexadecimal number, i.e. in base 16. In this format the letters a (or (A) to f (or F) count as hexadecimal numbers with the decimal values 10 to 15.

Numeric constants

Each whole number constant is interpreted as an integer if no l or u is appended. If the value range (-2147483648 bis 2147483647) is exceeded a syntax error is displayed (even though it is actually a semantic error, i.e. it relates to the characters).

In the script Output
DebugN(4294967295) Syntax Error
DebugN(4294967295u) [4294967295]

The following points can be deduced from this:

  1. A syntax error is possible in a numeric constant.
  2. Use the unsigned suffix if values greater than the maximum INT value range shall be displayed.

Error variables

The data type errClass can be used to store information on WinCC OA errors such as priority, type or text. Corresponding dyn types are possible. An error variable can be assigned to another error variable or string variable. You can read the individual attributes using suitable functions. Error variables are initialized to the default settings of priority INFO, type IMPL, code NOERR and a default text. The function getLastError() retrieves errors that have actually occurred.

Error Codes as text

Error codes are available as text. The error codes are available as enums and can be used as int by casting an error code. See example below. You can find the list of error codes in the chapter General CTRL Error Code Constants and error messages in the file wincc_oa_path/msg/<language>/_errors.cat.

main()
{
   int errorCode = (int)ErrCode::MANAGER_STOP;
   string errKeyword;
   sprintf(errKeyword, "%05u", errorCode);
   string errText = getCatStr("_errors", errKeyword);
   DebugTN("This is an error:" + errorCode + " as Text: " + errText);
}

Undefined variables

If an undefined variable or function is accessed at runtime, then the thread in question (program branch, see Threads and associated functions) is terminated immediately and an error message is issued.

Initializing variables

You may assign a value to a script global variable, right at the declaration:

Example

int x = 3;
main()
{
  //...
}

Use constant expressions for the initialization for example:

int x = 2 + 4;

or you can also assign a function (function has to be of the same type as the variable) to a variable at the declaration of the variable:

main()
{
  int x = myFunction();
  int y;
  int result = exampl_func(x,y);
/* exampl_func is a function that returns
                         an integer */
  DebugN(result);
}
int exampl_func(int x, int y)
/* return value of the function is of the same type
                   as the variable declared in main() */
{
  x = 2;
  y = 3;
  int sum;
  sum = x + y;
  return sum;
}

Variable declaration in a statement

Variables can also be declared in statements as shown in the example below (variable declaration in a for statement):

main()
{
  int i;
  int result = exampl_func(i);
  DebugN("return value:",result);
}
int exampl_func(int i)
{
  int a = 2;
  int b = 1;
  int multip;
  i = 4;
  for (int j = 0; j < i; j++)
//variable j declared in a for statement
  DebugN(j);
//j is valid only within the for statement
  multip = a * b;
  return multip;

//DebugN(j) would cause an error here since j is not valid anymore
}

Re-declaration of variables

A variable within a statement can be named exactly same as another variable in the code (the variable in the statement is only valid within it). In the example below you can see two variables named i. These variables are not the same although they are named same.

main()
{
  int i = 4;
  for (int i = 0; i < 7; i++)
//another i
  {
    DebugN(i);
  }

  DebugN(i);
/* returns 4 (the i that was declared first). Is not the same i as in the for statement */
}

"const" keyword

The const keyword marks the variables as constant, which means unchangeable. A variable can be defined with , for example, const int MAX = 23 and never may be changed afterwards. The same way parameters of functions may be defined as const, but the arguments may never be changed in the function.

Example

myFunc(const dyn_string &ds)
{
  ds[2] = "xxx";
// ==> ERROR
}

When an attempt is made to modify constant vectors and dyn_* types, no changes will be made and an exception will be thrown.

Library-global Variables - "global" keyword:

CTRL Library global variables are available in every function in a library. Local variables with the same name overwrite global variables.

Initialization of library global variables

Global variables are initialized after the library has been loaded. Arbitrary expressions and arbitrary functions can be used for a library if they are known at this time (meaning all expressions and functions that have been declared using #uses Libs and CtrlDLL). In the CTRL libraries you may also declare script global variables. Note that waiting CTRL functions such as delay() or dpGet() may not be used for the initialization of global variables.

You can declare a variable in a library as follows:

int a = 3;
const int b = 4;
global int c = 5;
  • The variable a is created so that it is copied to EACH CTRL script that is started in this manager. Thus, if you want to write functions in a CTRL library that are based on the fact that some variables exist and these variables must exist separately for each CTRL script, use this option to declare a variable.
  • The variable b is defined as a Manager wide (in each script) known constant.
  • The variable c is defined as a Manager global variable. This means the same effect as the addGlobal() function but the new keyword already works at the time of the declaration. This guarantees that these variables are created during a manager start when loading the CTRL libraries (and are also initialized).

"private global" variables

When declaring a "private global" variable it can be used like a global variable but is restricted to the library in which the variable has been declared!

Panel global functions and variables

For each panel a further script exists in the attribute-editor, where you declare functions and (script-global) variables, which are used by all objects of the panel (except Panel references) like variable defined in each script. The panel global variables exist only once and can be changed by all scripts. Panel references stay enclosed, i.e. two panel references means two variables.

Example

For the Event "ScopeLib" of the panel (see GEDI) the following function is defined:

DebugCode(string info)
{
  Debug(info
}

The buttons of the panel can debug information in the log viewer when a "Clicked" script is executed by calling the function DebugCode():

main()
{
  DebugCode("2th button");
}
  • Do not use panel global variables in the Initialize event of objects!
  • Inside the GEDI the initialization of the ScopeLib is only performed if at leas one #property has been defined.

"public", "private" and "protected"

Functions and variables can be defined as public (default) or private. the key word "protected" also exists but does not contain any functionality.

  • private Private methods can only be invoked by functions of the same library. Private variables are available in functions of the libraries, where they have been declared.
  • protected Reserved keyword (no functionality). Protected methods or variables are not used yet. protected variables will be used like public variables.
  • public Public methods can be invoked by methods of all libraries. Public variables are available in every function in the script/library. Public is the default for variables.

sizeof

Returns the length of string, dyn or mapping variables.

Example

dyn_int intVal;
intVal = makeDynInt(120,1,2,3,4,5,6);
string strVal = "TEST";

mapping mapVal;
mapVal["one"] = 1;
mapVal["two"] = 2;

DebugN(sizeof(intVal));
DebugN(sizeof(strVal));
DebugN(sizeof(mapVal));

"foreach" is a reserved keyword without functionality. Thus, the word cannot be used as variable name.

synchronized

The keyword Synchronized means that two threads cannot execute synchronized methods of the same object at the same time.

synchronized foo()
{
 // ...
}
//Only one thread can access the function. This is replacement for  i = foo();
uint bar;
foo()
{
  // ...
    synchronized  (bar)
    {
       //...
    }
 // ...
}

foo2()
{
  //...
    synchronized (bar)
    {
      //...
    }
  //
}

Both blocks as well as further blocks that are synchronized using "bar" are locked. Only one thread can access one of the blocks. Thus, changes of lists can be synchronized: "foo" would add and "foo2" would delete. The variable "bar" can be of any type and is like a mutex.

uint bar;
foo() synchronized (bar)
{
  //...
}

is a short form for:

foo()
{
  synchronized (bar)
  {
  }
}

This means that the whole function is synchronized using the variable "bar".

Important: The order of threads to be executed by the CTRL interpreter cannot be predicted by the executed code. There is no guaranteed order - only that they all will be executed "in parallel".

Reserved keywords

WinCC OA reserves the right to lock keywords for future use.

With version 3.18 the following keywords are reserved by WinCC OA and cannot be used as variable names:

  • function_ptr
  • shared_ptr
  • new
  • delete
  • nullptr
  • vector
  • using
  • namespace
  • friend
  • operator

Perform a syntax check via WCCOAui with start option "-syntax all" to look for invalid variable names in case of upgraded projects.

Waiting function in a nested function call

Waiting control functions like dpGet() (see chapter waiting control functions) can be used in nested function calls.

main()
{
  int i;
  int result = example(i);
  DebugN("Return value:",result);
}

int example(int i)
{
  int answ;
  string dp1 = "ExampleDP_Arg1";
  float val;
  answ = dpGet(dp1,val); /* Example executes a dpGet */
  DebugN("Datapoint:",dp1," ","Value:", val);
  return answ;
}

Casting

Casting means that a data type is converted into another data type.

(float)3
// converts the data type int to a float
(float)"1.23"
// converts the data type string to a float

Copying CTRL Variables

The WinCC OA CTRL variables are copied via "deep copy".