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 datapoint 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)
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_VARThe 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"
}
string
A string 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
The datatype 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).
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.
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.
Additional Notes and Hints
- Note that the data types
dpid,dyn_dpid,dpidentifieranddyn_dpidentifieronly exist in the API. To get dp_list information about a summary alert in CTRL, use a variable of the typedyn_string. For more information on API, see Introduction API. - Strings cannot be written or overwritten directly on a character-by-character basis.
Pointers
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
shared_ptr< shared_ptr<type>
> is not allowed.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;
The function equalPtr() can be used to compare the objects two pointers point to.
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
nullptr, otherwise the old object will be overwritten. The
reassignment can also be done with the function assignPtr(). 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.
Syntax:
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
nullptrconstant. This also enables the comparison to the nullpointer constant. - Both
shapeandshape<"">can hold any type of scriptable object and will not throw an exception.
Class Pointer
The class_ptr datatype is used to hold pointers to available class
or struct objects. It can only contain those types.
Syntax:
class_ptr <ClassName>
A class_ptr<void> can also be used, which can point to arbitrary
class objects.
The pointer is "non owning", and therefore only a "tracking" pointer.
The pointer is automatically set to nullptr when the object it
points to is destroyed.
The pointer to a class object is returned by getClassPtr().
A pointer can be assigned to a class_ptr variable as long as the
class_ptr variable is still null (equivalent to
shared_ptr), because if it is not null, an auto-dereferencing
takes place and otherwise the right side of the assignment is passed to the target
object. The assignment class_ptr variable = nullptr can always be
used. The pointer can also be changed with assignPtr(), even if it is already not null.
If possible, the class_ptr is auto-dereferenced.
Both assignPtr() and equalPtr() can accept class_ptr
arguments.
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>
Application Examples
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 vector 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.
