Data Type Details

Additional details for specific data types.

Anytype

The elements in this type of dynamic array can have different data types from each other.

  anytype any1, any2;
  dyn_anytype atype;
  any1 = 3.14;
//The data type of any1 is float.
  any2 = atype;
//The data type of any2 is dyn_anytype

Bit Patterns

A bit32 constant has to be entered with the suffix "U". For example +4294967295U

A bit64 constant has to be entered with the suffix "UL". For example: +18446744073709551615UL

Bit patterns cannot be written or overwritten directly on a character-by-character basis. Bit patterns must be changed using bit32 variables in Control.

Whereas pattern is of data type bit32, pattern[i] is of type bool; if string is of data type string, string[i] is of type char.

Blobs

Binary large objects (blobs) are used for flushing raw data through the WinCC OA system between the driver and user API.

Dynamic Arrays (dyn_ datatypes)

The individual elements of dynamic arrays are addressed in the form "array[i]", one being the smallest index. Dynamic arrays are initialized by assigning values to individual elements, or via dedicated array functions. The individual elements of an array of type dyn_int are of type int, the elements of a dyn_unint array are of type unsigned etc.

The elements of a data point attribute of type dynamic array cannot be set individually using the functions dpSet(), dpSetTimed(), and cannot be read individually using dpGet(), dpGetAsynch() or dpGetPeriod(). In the same way, dpConnect() functions cannot be performed on individual elements of a dynamic array. Original and online values are only sent to a dynamic array as complete values.

Enum

All enum elements are of type "int" and can be defined with or without an initial value. Duplicate names are not allowed, duplicate values are allowed.

Syntax:

enum EngineState
{
  Startup,
  Off =
2,
  On =
4,
  Error
};

Initial values can only be single constant values or other already defined names in the enum. Like in C, if an item has no initial value, it automatically gets the previous members value + 1, starting with 0.

In the above example the result is the following list of items:

Startup = 0, Off = 2, On = 4, Error = 5

To use an enum value somewhere in the code, use the syntax:

EnumName::Value

You can also declare variables of an enum type, but it can only be assigned a value which is in the list of items. If another value is assigned, the previous value remains.

The initial value of an enum instance is the value of the first element.

Example

EngineState eState;
// is initialized with 0
  eState =
2;
// OK, since EngineState::Off is 2
  eState =
EngineState::On;
// OK, since On is in the list
  eState =
64;
// Not allowed, since 64 is not defined. Value remains 4

You can not directly assign an enum value to an int. Therefore, an explicit cast is necessary.

Example

int x =
EngineState::On;
// Not allowed, an explicit cast is required
int x = (
int)
EngineState::On;
// OK

This also applies to a direct comparison between an enum value and an int value.

Example

if ((
int)
_eCONNECION_STATE::STATE_Connected ==
1)
If an integer value is compared to an enum value without an explicit cast, following warning can be found within the LogViewer:
WCCOAui (1), YYYY.MM.DD
                    hh:mm:ss.ms, IMPL, WARNING, 50, Default branch called, IntegerVar, operator=,
                    cannot assign variable of type CLASS_VAR

The code will continue to be executed and no interruption will occur.

int

Note that the number 2147483648 can be used as a constant but cannot be stored as a value.

langString

Language string (see also Multilingual functionality).

The assignment of a value to a langString such as:

fails, because the index operator only allows read operations.

main(mapping event)
{
  langString a, b;
  setLangString(a, getLangIdx("hu_HU.utf8"), "Hungarian");
  a[getLangIdx("hu_HU.utf8")] = "anything";
  Debug(a);
}

Specific member functions are available for the langString data type.

long

A "long" constant has to be entered with the suffix "L".

Example

 0x7FFFFFFFFFFFFFFFL

mapping

Mappings save arbitrary key/value pairs. The keys and values are saved in two arrays (one for keys and one for values). A mapping with key:value pairs "one": 1, "two":2, "three":3 looks internal as follows:

key value
"one" 1
"two" 2
"three" 3

See chapter Mappings for more information.

Specific member functions are available for the mapping.

mixed

Contrary to anytype the variable type mixed gets each time a new type as shown in the example below:

examp_func()
{
  anytype a;
  mixed m;
  a  = false;
  m = false;
  DebugN(a);
//Returns 0 or FALSE
  DebugN(m);
//Returns 0 or FALSE
  a = "example";
  m = "example";
  DebugN(a);
//Returns 1 or TRUE
  DebugN(m);
//Returns "example"
}

shared_ptr

The shared pointer data type which is available in WinCC OA can be used like a template.

shared_ptr<int> object1;

Creates a shared_ptr object with the name object1 that points to a new object of the named data type. To create such an object, use the "new" expression.

shared_ptr<Base> object1 = new Base;

In this case <Base> is a new class. The data type used for the shared_ptr can either be a user-defined type (class/struct/enum) or also a standard data type like int, float, etc.

shared_ptr<int> object1 = new int;

You can assign the shared_ptr to another shared_ptr of the same (or compatible) type.

shared_ptr<Base> object2 = object1;

Thus, two pointers pointing at the one and only Base instance. When object1 gets out of scope (or the nullptr is assigned to it), object2 still has the pointer to the instance until it gets out of scope as well.

Using pointer to pointer like shared_ptr< shared_ptr<type> > is not allowed. Also a reference parameter to a shared_ptr is not possible, e.g.:
int foo(shared_ptr<int> &ref_to_ptr)
.

You can also use the "void" datatype, which creates a pointer which can point to any other data type.

shared_ptr<void> p = new string;

Downcasting of a shared_ptr is also allowed:

Classes B is inherited from class A

shared_ptr<A> pA = new B;
shared_ptr<B> pB;

pB = pA;

New expression

The "new" expression can be used with or without arguments, e.g.:

shared_ptr<int> pi = new int;                 // no argument
shared_ptr<int> pi = new int();               // no argument
shared_ptr<int> pi = new int(77);             // with initial value
shared_ptr<int> pi = new int(someFunction()); // with initial value
shared_ptr<Enum> pe = new Enum(Enum::One);    // with initial value
shared_ptr<Base> pb = new Base;               // constructor without argument
shared_ptr<Base> pb = new Base(1, 2, 3);      // constructor with arguments

Note: pointer to pointer like shared_ptr< shared_ptr<type> > is not allowed.

Also a reference parameter to a shared_ptr is not possible, e.g.: int foo(shared_ptr<int> &ref_to_ptr).

You can also mimic the reference case, but only if the objects you want to shortcut are also shared_ptr instances that were created by using "new". e.g.:

  mapping m;
  m[1] = new int;
  shared_ptr<int> p = m[1];
  p = 77;

  DebugN(m[1]);  => 77

Auto-dereferencing

An auto-dereferencing of shared_ptr variables is available. The auto-dereferencing is different than in C++. It works similarly to anytype/mixed since internally they also point to an instance of some other data type but when using them, they automatically get the real/final object. e.g.:

  mapping m;

  m["object"] = new Base;

  m.object.x = 88;  // not as in C++:  m.object->x = 88;

Auto-deref is always done when there is a target the pointer points at. e.g.

  shared_ptr<string> s1;               // nullptr
  shared_ptr<string> s2 = new string;  // points to a string
  s1 = s2;

A new function equalPtr(shared_ptr, shared_ptr) allows to compare if both given pointers point to the same object in memory:

bool equalPtr(s1, s2)
VORSICHT:

When the pointers point to different objects of the same type and are then assigned the same value, the function returns "false" because it is not the same object. e.g.:

  s1 = new string;
  s2 = new string("Hello");
  s1 = s2;  /* auto-dereferencing is done.
            s1 and s2 point to different string objects
            but both strings now contain the same value "Hello" */

  equalPtr(s1, s2)  => false

When comparing with the nullptr constant, no auto-deref is done and the pointer is compared.

You can, for example, check if the pointer contains a value:

  Shared_ptr<XY> spTest;

  if( spTest ) //compared with nullptr
  {
    //...
  }

Nullptr - free the memory

To free the pointed at object, just assign a nullptr to the pointer. When the last pointer pointing at an object is out of scope or a nullptr is assigned to it, the pointed at object is deleted.

  shared_ptr<string> s = new string;   // memory allocated
  s = "Hello";                         // memory written
  s = nullptr;                         // memory freed
Anmerkung:

Before a new pointer can be assigned to a pointer, it has to be set to nullptr, otherwise the old object will be overwritten. The reassignment can also be done with the function assignPtr().

VORSICHT:

Note that some CTRL keywords are used internally and are thus no longer allowed to be used for other things such as variable names: shared_ptr, new, delete, nullptr

If you create a class and an object of this class contains a shared_ptr and this shared_ptr points to the object itself, this reference never goes out of scope and is not automatically deleted. You must set the member variable to a nullptr.

This also applies if two objects point to each other, the objects are not automatically deleted and both will never go out of scope. Set the variables to nullptr.

shape

The shape data type can hold pointers to scriptable objects.

shape

This data type can also be annotated with a specific shape type. For a list of available shape types see "shapeType". In addition, the names of user-generated EWOs can be used.

E.g. the user created a "UserCreated.ewo" plugin, then the string "UserCreated_ewo" is also possible.

shape<"datatype">

Using this syntax, the shape variable is only allowed to hold the specified shape type. If a different shape types is used, an exception will be thrown. As a consequence, even unassigned, the completion list for the given shape type can be shown in the script editor.

Example

Assigning a shape to the shape variable "line" within a panel containing the line "Line1" and the rectangle "Rectangle1".

  shape<"LINE"> line;
  line = Line1;        //is allowed
  line = Rectangle1;   //will throw an exception
  • In contrast to shared_ptr<typeName>, the "typeName" for the shape data type is a string constant and must therefore be written including the quotation marks.

  • It is possible to assign the nullptr constant. This also enables the comparison to the nullpointer constant.

  • Both shape and shape<""> can hold any type of scriptable object and will not throw an exception.

string

Strings can be any number of characters. However, their size depends on the operating system as well as on the free disk space and main memory.

Strings cannot be written or overwritten directly on a character-by-character basis.

time

Time is the Unix time since 1.1.1970. 64Bits are used for the seconds. The milliseconds are saved in an additional unsigned short.

Windows is not able to deal with negative times, e.g. in calculations. Thus, an integer value which specifies the seconds must be converted into "time" beforehand.

Example

int i = -86400;
time c = getCurrentTime();
DebugN((time)(period(c) + i));

Example

Time in milliseconds:

int
  i = -86400;
time c = getCurrentTime();
DebugN((time)((float)c + i));

For Linux a conversion is not required.

uint

A "uint" constant has to be entered with the suffix "U".

Example

 +4294967295U

ulong

A "ulong" constant has to be entered with the suffix "UL".

Example

 0x7FFFFFFFFFFFFFFFUL

unsigned

Unsigned describes a positive integer value.

Note that when the value 4294967295 is assigned to an unsigned variable, a syntax error is shown. The error is shown because all numbers are handled as integers per default. To assign the value 4294967295 to the unsigned variable, the character "u" (unsigned) has to be used:

unsigned f = 4294967295u;

Use the sign also in case of hexadecimal variables and the value 4294967295.

va_list

An arbitrary number of parameters is defined via va_list. va_start sets the parameters into the va_list variable. va_arg is like an iterator and it handles always the next parameter of the va_list variable. va_end stops the handling of the parameter list (see also Parameters for further information to this variable type).

vector

The vector is a configurable data type (similar to a shared_ptr or the dyn_ variables) that can contain multiple elements of a specified type.

Syntax:

vector<data_type>

Example:

A vector holding a list of int elements:

vector<int>

The type can also be another vector:

vector< vector<int> >

Writing vector<vector<int>> is syntactically not correct, since two ">" in a row without a blank between each other are treated as a shift operator.

The elements within a vector can be addressed via their index. The index operator [] of a vector starts with 0 (ZERO). In vectors the index operator can only be used for elements which are already in the vector. It is not possible to assign a value to an index that is not already present. This means that additional elements should be added with specific functions (e.g.: the member functions append() or prepend()).

  vector<int> v = makeVector(1, 2, 3, 4);

  v.append(5);    // adds element as last element
  v.prepend(0);   // adds element as first element

Vectors can only contain elements of the same defined type, meaning that a vector<int> can only hold int values. The exception to this are vector<void>, vector<anytype> and vector<mixed>. If the vector contains a class or a shared_ptr to a class, it is also possible to add derived classes (or a shared_ptr to it) to the vector.

A vector cannot be directly converted to a string. Use jsonEncode(vector) if you want to serialize the vector to a string.

Vectors & dyn data types

The functionality of a vector is comparable to the various dyn_ data types. As long as the data types are the same, a vector can be assigned to a _dyn and vice versa. This means that a vector can also be initialized with makeDyn functions. eg.:

vector<string> v = makeDynString("a","b","c");

As a special case it is also possible to assign any vector to a dyn_anytype or a dyn_mixed.

The biggest difference between vectors and dyn_ variables is the index. For vectors this index starts at 0 while dyn_ variables start at 1. This influences, for example, the iteration with a for-loop:

vector<int> v = makeVector(1, 2, 3, 4);
for (int i = 0; i < v.count(); i++)
{
  DebugN("new value:", v[i]);
}

dyn_int dynInt = makeDynInt(1, 2, 3, 4);
for (int i = 1; i <= dynlen(dynInt); i++)
{
  DebugN("new value:", dynInt[i]);
}

vector<void>

The void data type for a vector allows to add any data type. A vector<void> is similar to a dyn_anytype, but a dyn_anytype is a dyn_ containing anytype variables, which themselves point to any other type. In terms of performance and memory consumption, the vector<void> is better, since it directly holds the final pointers to whatever datatype was given. The following function allows to create a vector<void>:

vector<void> makeVector(...)

A vector<void> can be assigned to any other vector or dyn_ as long as the datatypes of all items match the needed datatype. Otherwise an exception is thrown.

dyn_int di = makeVector(1,2,3);

vector< shared_ptr<MyObj> > myVec = makeVector(new MyObj(1), new MyObj(2), new MyObj(3));

Type alias

To make working with nested data types like vector< vector< shared_ptr<SomeClass> > > easier, the keyword "using" can be used the following way:

using AliasName = existingType

A type alias can also be used for any other type (e.g. int, vector, class, ect.). It is defined like a class declaration in a script outside of any function. The alias can then be used in the same way the full expression would be used as the parser resolves the alias name to the original type. e.g.:

using MyVec = vector < vector< shared_ptr<SomeClass> > >
using myInt = int;
using MyClass = SomeClass;
using vec_str = vector<string>;

Specific member functions are available for the vector data type.

Notes and Pointers

  • Note that the data types "dpid", "dyn_dpid", "dpidentifier" and "dyn_dpidentifier" only exist in the API. To get dp_list information about a summary alert in CTRL, use a variable of the type dyn_string. For more information on API, see Introduction API.
  • Strings cannot be written or overwritten directly on a character-by-character basis.

Conversion of decimal numbers into floating point numbers

The norm IEEE 754 comprises representations for binary floating point numbers in computers. Furthermore, the norm defines methods for mathematical operations such as roundings. For binary floating point numbers there are two formats available: 32 bit (single precision) and 64 bit (double precision).

WinCC OA provides the C++ data types float and double in CTRL as float and double. Internally these types are mapped to a float variable. The actual value of a float variable is, however, saved as a double. Thus, it provides double precision for floating point numbers.

Arithmetic operations with floating point numbers are more complicated than operations with binary values.

A decimal number cannot be displayed as a floating point number precisely (rounding accuracy) independent of whether single or double precision is used. The conversion of a decimal number into a floating point number is not described in detail here since it is a basic arithmetic operation of computer science.

When dealing with peripheral devices that only support single precision floating-point numbers or when configuring alert ranges for decimal values, make sure to understand the inherent limitations of the IEEE 754 floating-point numbers before using them in production systems.

Member functions of standard data types

The following standard data types provide member functions. These can be called with dot-notation, similar to calling a function of a class. In case of functions which return an integer without explicit explanation, the return value can be ignored since all errors will throw an exception. T in the following lists depicts the data type. T& shows that the returned value is a reference to the value inside the vector and can be directly assigned to. E.g. vec.at(12) = 123;

All member functions use a zero(0)-based index. This also applies to dyn_types.

All functions will throw an exception if the wrong number of arguments is passed.

mapping

A list of all mapping member functions can be found here.

string

A list of all string member functions can be found here.

langString

A list of all langString member functions can be found here.

Vector & dyn_

A list of all vector / dyn_* member functions can be found here.

Numerical Values

Numerical values with leading zeros are interpreted as octal numbers, those with leading 0X are treated as hexadecimal. CAUTION: If the following declarations are made an error message is generated for the second version, since these numbers are interpreted as octal values.

No error:

dyn_int time = makeDynInt( (((04*60)+00)*60) );

with error:

dyn_int time = makeDynInt( (((09*60)+00)*60) ).

Syntax errors would also occur for iHour=09 and iMinute=08.