CoDeSys размер ссылки на указатель - PullRequest
0 голосов
/ 03 июля 2018

Используя Codesys v2.3, я пытаюсь создать функциональный блок, который проверяет размер данных указателя, чтобы не записывать в части памяти больше этого.
Пример:

VAR_INPUT
    pData:        POINTER TO REAL;    // Or pointer to WORD or ARRAY[1..x] ...
END_VAR
VAR_OUTPUT
    DataSize:     DWORD;
END_VAR

IF SIZEOF(pData^) <> 4 THEN 
    RETURN;
END_IF

DataSize := SIZEOF(pData^);

Теперь, если бы я поместил адрес байта в pData этого блока, IF все равно бы проверил, поскольку разыменованный указатель, кажется, только возвращает размер того, на что мы указываем (REAL в данном случае).

Я знаю, что в качестве входных данных может потребоваться размер, но это может быть потенциальной проблемой, если он пропущен или введен неверно, так как это может повлиять на программу другими способами

Есть ли способ проверить размер данных, на которые указывают данные, избегая при этом внешних вводов?

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Зачем вам нужна такая функция, просто чтобы определить размер переменной, пока эта функция уже существует?

Все, что вам нужно сделать, это вызвать SIZEOF() прямо внутри вашей программы. Вам не нужно использовать указатели. Как я понимаю, вы используете их, потому что вы хотите сделать входную переменную универсальной любого типа, а не потому, что вы используете указатели в своей программе. Таким образом, исходные переменные распределяются напрямую.

Ваша функция - попытка создать обтекание вокруг SIZEOF() без каких-либо изменений в алгоритме расчета, затем просто используйте SIZEOF(), поскольку для этого и предназначена эта функция.

Скажите, почему вы пытаетесь создать отдельную функцию, и я Изменим ответ соответственно.

Мое предположение, что вам нужно проверить, является ли переменная нужного вам размера. Тогда вы можете сделать функцию.

FUNCTION IsSize : BOOL
    VAR_INPUT
        VarSize: INT;
        CompareTo: INT;
    END_VAR
    IsSize := (VarSize = CompareTo);
END_FUNCTION

И тогда вы можете назвать это так

VAR
    MyVar: REAL;
END_VAR

IF IsSize(SIZEOF(MyVAR), 4) THEN
    // DO something
END_IF

Редактировать: работа с массивом

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

FUNCTION ArrSize : BOOL
    VAR_INPUT
        MyArr: POINTER TO ARRAY[0..1000] OF BOOL;
        ArrNum: INT; (* Number of array elements *)
        ArrStart: INT; (* First index of an array *)
    END_VAR
    VAR
        iCount : INT := 0;
    END_VAR

    FOR iCount := ArrStart TO ArrNum DO
        MyArr^[iCount] := TRUE;
    END_FOR
END_FUNCTION

Тогда в коде вы можете

VAR
    aTest: ARRAY[0..20] OF BOOL;
END_VAR

ArrSize(ADR(aTest), SIZEOF(aTest), 0);
0 голосов
/ 03 июля 2018

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


Решения для других сред:


Для TwinCAT 3 можно было бы создать решение с одним входом, используя T_Arg и такие помощники, как F_INT, но я думаю, что в Codesys 2 их нет (кто-нибудь подтверждает?). В этом решении вам в любом случае придется изменить вызов функции, чтобы указатель не был вводом.

В этом решении вы можете создать функцию с вводом T_Arg. А затем вызовите его, используя вспомогательную функцию для каждого типа данных. От T_Arg можно получить тип данных, размер и местоположение данных.

FUNCTION_BLOCK FB_Test
VAR_INPUT
    Test : T_arg;
END_VAR

Test.eType; //Data type
Test.cbLen; //Variable data length in bytes
Test.pData; //Pointer to data

И назвать это:

test is an instance of FB_Test
//INT for example
//Now the cblen = 2
test(
    Test := F_INT(PointerToInt^) 
);

//REAL for example
//Now the cbLen = 4
test(
    Test := F_REAL(PointerToReal^) 
);

Это, возможно, немного оффтоп, так что извините, надеюсь, это кому-нибудь поможет. Все еще надеемся, что кто-нибудь узнает лучшее решение.

EDIT На самом деле нашел другое отличное решение, но я думаю, что это также только для TwinCAT 3. Просто хотел опубликовать его здесь тоже.

Используя тип данных ANY, можно указать что угодно в качестве параметра и получить его размер. Разница в том, что он не примет POINTER в качестве ввода.

FUNCTION_BLOCK FB_Test2
VAR_INPUT
    Test : ANY;
END_VAR
VAR_OUTPUT
    Size : DINT;
END_VAR
//diSize contains size of the input data type
size := Test.diSize;

Использование:

//test2 is an instance of FB_Test2
//Output "Size" is 4, as this is a REAL
test2(
    Test := PointerToReal^
);
...