Показано с 1 по 10 из 10

Тема: stop := (size - SIZEOF(pt)) / SIZEOF(pt); как это работает?

  1. #1

    Unhappy stop := (size - SIZEOF(pt)) / SIZEOF(pt); как это работает?

    в oscat_basic есть множество функций работы с массивами.

    у большинства из них(может и у всех, не проверял) в начале есть строчка как в заголовке темы
    весь текст ниже
    Код:
    FUNCTION ARRAY_MIN : REAL
    VAR_INPUT
    	pt : POINTER TO ARRAY[0..32000] OF REAL;
    	size : UINT;
    END_VAR
    VAR
    	i: UINT;
    	stop: UINT;
    END_VAR
    -------------------------
    stop := (size - SIZEOF(pt)) / SIZEOF(pt);
    array_min := pt^[0];
    FOR i := 1 TO stop DO
    	IF pt^[i] < array_min THEN array_min := pt^[i]; END_IF;
    END_FOR;
    вызов её выглядет так
    X:=oscat_basic.ARRAY_MIN(ADR(some),SIZEOFF(some))

    не понимаю как работает первая строчка,
    к примеру some массив из 10 значений REAL
    тогда на вход фунции попадет указатель на массив и число 40 (размер массива в байтах)
    в коде функции получается
    stop:=(40-40)/40

    иии какой в этом смысл? но это работает же. в переменной stop в итоге размер массива(количество значений real)
    что я не так понимаю?

  2. #2
    Супер Модератор Аватар для Евгений Кислов
    Регистрация
    27.01.2015
    Адрес
    Москва
    Сообщений
    12,066

    По умолчанию

    к примеру some массив из 10 значений REAL
    тогда на вход функции попадет указатель на массив и число 40 (размер массива в байтах)
    Тут вы правы.

    в коде функции получается
    stop:=(40-40)/40
    А вот здесь нет.

    SIZEOF(pt) в данном случае возвращает размер указателя. В реализации CODESYS - размер указателя всегда равен 32 бита (4 байта) на 32-битных рантаймах.
    На 64-битных рантаймах он равен 64 бита, но во времена разработки OSCAT поддержки таких рантаймов еще не было.

    В итоге: (40-4)/4 = 9

    Логично - у вас массив из 10 элементов, индексация элементов ведется с 0 - значит, индекс последнего элемента и правда равен 9.

  3. #3

    По умолчанию

    Цитата Сообщение от Евгений Кислов Посмотреть сообщение
    SIZEOF(pt) в данном случае возвращает размер указателя. В реализации CODESYS - размер указателя всегда равен 32 бита (4 байта) на 32-битных рантаймах.
    На 64-битных рантаймах он равен 64 бита, но во времена разработки OSCAT поддержки таких рантаймов еще не было.

    В итоге: (40-4)/4 = 9
    Спасибо. Я догадывался, о чем то подобном. Да, ведь через ADDR мы получаем только адрес начала массива безотносительно его размеров . Только непонятно, что задумал автор? Ведь в других системах sizeoff(адрес) будет зависеть от количества адресуемой памяти видимо. А размер real так и останется 4 байта. Или 8 байт байт и это универсальный код получается?

  4. #4
    Супер Модератор Аватар для Евгений Кислов
    Регистрация
    27.01.2015
    Адрес
    Москва
    Сообщений
    12,066

    По умолчанию

    Только непонятно, что задумал автор? Ведь в других системах sizeoff(адрес) будет зависеть от количества адресуемой памяти видимо.
    Библиотека разрабатывалась для конкретного набора систем (CoDeSys V2.3, PCWORX и т.д.), про которые было известно, что размер указателя там равен 4 байта.
    При портировании библиотеки на другие системы - отвественность за подобные исправления лежит на авторе порта.

  5. #5

    По умолчанию

    Цитата Сообщение от Евгений Кислов Посмотреть сообщение
    ...про которые было известно, что размер указателя там равен 4 байта....
    в таком случае это излишнее усложнение и строку

    Код:
    stop := (size - SIZEOF(pt)) / SIZEOF(pt);
    можно было написать проще и понятнее для человека:

    Код:
    stop := (size - 4) / 4;
    хотя, конечно для компилятора по итогу все равно, так как SIZEOF(pt) на начальном этапе компиляции заменяется на константу 4.

    PS. кстати, я задался этим вопросом потому, что переделывал под себя пару ФБ из oscat_basic.
    все блоки работающие с массивами в этой библиотеке предназначены для массивов REAL.
    А мне нужны были для INT массивов.
    Я, не долго думая, взял исходники и переделал их под INT, но допустил такую вот ошибку (выше)

    PPS. вот в другом месте ребята этот вопрос решили по другому:

    Код:
    stop := SHR(size,2)-1;
    но это мне было мне понято. побитовый сдвиг вправо на два знака, равносилен делению на 4,
    и для работы с INT достаточно было сдвигать на 1, чтобы получить деление на 2.
    Последний раз редактировалось Schneider; 18.04.2023 в 07:20.

  6. #6

    По умолчанию

    Цитата Сообщение от Schneider Посмотреть сообщение
    и строку
    Код:
    stop := (size - SIZEOF(pt)) / SIZEOF(pt);
    можно было написать проще и понятнее для человека:
    Код:
    stop := (size - 4) / 4;
    Так не принято делать во всех языках программирования. То, когда подставляют непонятные числа, называется "Магические числа" и за это во многих компаниях серьёзно наказывают.
    Поэтому здесь они и применили SIZEOF, и это правильно, хоть даже и будет известно что при 32-битных указателях это всегда равно 4.
    Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте. © Steve McConnell
    Мой рабочий блог со статьями про щиты и автоматику ОВЕН - Cs-Cs.Net | Почта: Info@Cs-Cs.Net

  7. #7

    По умолчанию

    Спасибо, интересная статья! Не знал, но на практике в своем коде сталкивался с таким,
    и интуитивно сам старался избавлятся от таких вещей, кстати. Теперь буду пользоваться осознано.

    Тогда в продолжение её логики могу добавить, что выражение с числами:

    Код:
    stop := (size - 4) / 4;
    вполне понятно, и ничего "магического" в цифре 4 нет, поскольку REAL он же FLOAT по смыслу во всех системах занимает 4 байта.
    а брать размер адреса в качестве размера REAL - это ли не запутает еще больше?

    а пример из другого блока той же oscat_basic так же работающей с массивами REAL и написаный ровно в таком же месте с такой же целью:

    Код:
    stop := SHR(size,2)-1;
    вот вам классический пример "магических чисел" в таком случае.

    Понятней тогда написать было типа:

    Код:
    SizeOfReal:USINT:=4;
    stop := (size/SizeOfReal)-1;

  8. #8

    По умолчанию

    Цитата Сообщение от Cs-Cs Посмотреть сообщение
    Поэтому здесь они и применили SIZEOF, и это правильно, хоть даже и будет известно что при 32-битных указателях это всегда равно 4.
    Вот по моему, не совсем правильно, поскольку в 64 битной системе адрес будет 8ми байтный а REAL останется 4 байта, вроде, и тогда не переносимость кода.

  9. #9
    Пользователь
    Регистрация
    04.11.2013
    Адрес
    Минск, Беларусь
    Сообщений
    26

    По умолчанию

    Цитата Сообщение от Schneider Посмотреть сообщение
    Вот по моему, не совсем правильно, поскольку в 64 битной системе адрес будет 8ми байтный а REAL останется 4 байта, вроде, и тогда не переносимость кода.
    >что задумал автор?
    >как это работает?
    Автор хотел написать переносимый код, написал неправильно, но получил работающий код, потому-что SIZEOF(POINTER) и SIZEOF(REAL) оба равны 4.

    Переносимый вариант должен выглядеть как-то так:
    Код:
    stop := (size - SIZEOF(pt^[0])) / SIZEOF(pt^[0]);

  10. #10

    По умолчанию

    Да, так лучше всего, точно.

Похожие темы

  1. SIZEOF в codesys 2.3
    от leoSMD в разделе ПЛК1хх
    Ответов: 7
    Последнее сообщение: 17.04.2023, 18:48
  2. ПЛК110-(М02) выключатель run-stop
    от confiden в разделе ПЛК1хх [М02]
    Ответов: 9
    Последнее сообщение: 06.01.2018, 17:37
  3. ПЛК100, безопасное отключение в STOP
    от Alor в разделе ПЛК1хх
    Ответов: 6
    Последнее сообщение: 27.04.2010, 19:22
  4. Как правильно пользоватся Callback STOP?
    от !nferno в разделе ПЛК1хх
    Ответов: 0
    Последнее сообщение: 22.04.2009, 08:51
  5. Start/Stop протокола Owen
    от Dmitry в разделе ПЛК1хх
    Ответов: 1
    Последнее сообщение: 13.08.2007, 22:21

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •