Приведение типа C из Ua_Variant

#c #pointers #open62541

#c #указатели #open62541

Вопрос:

Я пытаюсь понять, что делает приведение типов в следующем коде

 UA_Variant Variant; 
Int32_t Variable; 

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

Это структура 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;
 

Что происходит в этой строке

 variable = *(int32_t *) Variant.data; 
 

является ли это приведением данных в Variant к int32_t, а затем переносом указателя на это в переменную, и если да, то почему я могу распечатать значение, сохраненное в переменной?

Ответ №1:

Давайте распакуем это утверждение в несколько этапов: *(int32_t *) Variant.data

Во-первых, у нас есть Variant.data , который является a void* в соответствии со UA_Variant структурой. Это означает, что это просто число, содержащее адрес памяти.

Затем, когда (int32_t *) вы приведете это void* к a int32_t* . Данные, на которые указывает, Variant.data будут интерпретироваться как указатель на данные типа int32_t . Я настаиваю на интерпретации, а не приведении.

Наконец, вы разыменовываете его с * помощью оператора. В результате переменная variable содержит данные, на которые указывает Variant.data интерпретируется как 32-разрядное значение со знаком. Это означает, что если бы данные, на которые указывает by Variant.data , были каким-либо другим типом данных, таким как float s, результирующее значение в вашей переменной казалось бы случайным и зависело от неопределенного поведения. Это связано с тем, что разные платформы по-разному реализуют каждый тип данных.

Поскольку эта переменная является значением, вы можете распечатать ее, как и любую другую.

Комментарии:

1. Спасибо, думаю, теперь я понял.

Ответ №2:

data Член вашей UA_Variant структуры определяется как void* , что означает, что он указывает на объект неопределенного типа. Такие «пустые указатели» не могут быть разыменованы.

Итак, если конкретный data ваш элемент Variant указывает на объект, который должен обрабатываться как объект int32_t типа, то сам указатель сначала должен быть приведен к правильному типу указателя ( int32_t* ); затем его можно разыменовать.

Строка variable = *(int32_t *) Variant.data; , возможно, более понятна с некоторыми добавленными круглыми скобками. Это эквивалентный код:

 variable = *( (int32_t *)(Variant.data) );