2

I'm trying to understand what the typecasting is doing in the following code

UA_Variant Variant; 
Int32_t Variable; 

variable = *(int32_t *) Variant.data; 
printf("%d", variable);

This is the structure of the UA_Variant

typedef struct 
{
    const UA_DataType *type;      /* The data type description */
    UA_VariantStorageType storageType;
    size_t arrayLength;           /* The number of elements in the data array */
    void *data;                   /* Points to the scalar or array data */
    size_t arrayDimensionsSize;   /* The number of dimensions */
    UA_UInt32 *arrayDimensions;   /* The length of each dimension */
} UA_Variant;

What is happening in this line

variable = *(int32_t *) Variant.data; 

is it type casting the data in Variant to int32_t then taking the pointer of that into the variable and if so why can I print out the value stored in variable?

Parko
  • 23
  • 6

2 Answers2

3

Let's unpack this statement in multiple steps: *(int32_t *) Variant.data

First, we have Variant.data which is a void* according to the UA_Variant struct. This means that it is simply a number containing a memory address.

Then, with (int32_t *) you cast that void* to a int32_t*. The data pointed to by Variant.data will then be interpreted as a pointer to data of type int32_t. I insist on interpreted not casted.

Finaly, you dereference it with the * operator. As a result, the variable variable contains the data pointed to by Variant.data interpreted as a signed 32 bit value. This means that if the data pointed to by Variant.data was some other datatype like a floats, the resulting value in your variable would seem random and depend on undefined behavior. This is because different platforms implement each datatype differently.

Since this variable is a value, you can print it like any other.

Henry Le Berre
  • 910
  • 9
  • 18
2

The data member of your UA_Variant structure is defined as void*, which means it points to an object unspecified type. Such "void pointers" cannot be dereferenced.

So, if the particular data member of your Variant points to an object that is to be treated as an object of int32_t type, then the pointer itself must first be cast to the correct pointer type (int32_t*); then, it can be dereferenced.

The line variable = *(int32_t *) Variant.data; is perhaps more readily understandable with some added parentheses. This is equivalent code:

variable = *( (int32_t *)(Variant.data) ); 
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83