Программистские задачки и хитрости

Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

uralpt писал(а): 13 мар 2021, 13:34 Стояла задача в битовом представлении слить 2 значения char в строку как X + Y = XY...

Код: Выделить всё

// нужно в битовом виде слить 2 значения char в строку как X + Y = XY

#include <iostream>
#include <bitset>

char mess[2];
unsigned long w; //почему такой тип?


int main()
{
    mess[0] = 0b01100100;  //если компилятор заругается, можно написать 'd'
    mess[1] = 0b10000000;  //можем написать 'Ђ';
    
    std::cout << std::bitset<8>(mess[0]) << std::bitset<8>(mess[1]) << "\n"; //выводим наши первичные значения 

    w = mess[0] << 8 | mess[1];
    std::cout << std::bitset<16>(w);  //и сверяем со слитой строкой
}

//можно развить темы битового умножения, деления и т.п. :))
я бы делал как то так...

собственно не понятно причем тут какой либо endian, это про расположение в памяти, а не про остальное, имхо.

ну и вообще битовые операции и т.д. я б крутил с явными типами вида uint8_t...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

Чтобы было понятней и компилятору и себе, а также исключить возможные разночтения, я бы так сделал:

Код: Выделить всё

uint8_t mess[2];
uint32_t w;
.............

w = ((uint32_t)mess[0] << 8) + (uint32_t)mess[1];
Типы и их преобразования прописаны в явном виде. Также в явном виде обозначен сдвиг на 8 разрядов, вместо умножения на 256.
Компилятор, скорее всего, сам бы вписал сдвиг вместо умножения, но так для себя понятнее.
Чудес не бывает. Бывают фокусы.
Аватара пользователя
MX_Master
Мастер
Сообщения: 7465
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3088
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

А вместо сложения компилятор подставит побитовое ИЛИ?
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Duhas писал(а):

Код: Выделить всё

unsigned long w;  //почему такой тип?
Этот тип выдернут из тела программы, не стал исправлять. Изначально код делался для самописанной функции хеширования, это значение целиком вмещает хеш. Все на примитивном уровне, но для бытового секретика при никому неизвестном алгоритме - вполне себе.
В любом случае, решение с uint_t более правильно. Буду заново переписывать.
Не ожидал я такой подставы от char :))
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
gcc при "-O2" скорее всего всю эту строчку в две инструкции пересылки превратит. В принципе можно и самому так написать, но это будет ненаглядно.
uralpt писал(а): Не ожидал я такой подставы от char :))
В gcc и некоторых других компиляторах есть флаг, делающий char по умолчанию unsigned.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
Нет смысла. Обе операции простые, выполняются за одинаковое количество тактов. В отличие от умножения, которое не факт, что выполняется так же быстро.
Чудес не бывает. Бывают фокусы.
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Duhas »

Сергей Саныч писал(а): 14 мар 2021, 11:47
MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
Нет смысла.
не соглашусь, во-первых, ИЛИ точнее описывает смысл выполняемых действий, во-вторых, если окажутся вдруг ненулевые биты в неположенных местах искажение данных будет выше со сложением, хотя это уже за уши тяну..
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Основное различие - это какие биты регистра статуса могут изменится в результате операции. Например ИЛИ никогда не вызовет переполнения.
Так-же операция 0 | (int8_t)(-128) на многих процессорах с разрядностью более 8 бит не вызовет установки бита отрицательного результата, а операция 0 + (int8_t)(-128) вызовет.
И если после таких операций идёт if/while, то компилятор может создать на одну инструкцию больше или меньше.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

Serg писал(а): Основное различие - это какие биты регистра статуса могут изменится в результате операции. Например ИЛИ никогда не вызовет переполнения.
В данном конкретном случае ни переполнения, ни переноса возникнуть не может ни при ИЛИ, ни при сложении. Если исходные данные подготовлены правильно, ситуация 1+1 не возникнет ни в одном разряде.
Чудес не бывает. Бывают фокусы.
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Данный конкретный случай не интересен - с ним уже разобрались.
Сейчас я про то, что казалось-бы тождественные операции могут давать разные результаты, да ещё и зависящие от модели процессора.
Ты ведь наверняка знаешь, что в вычислительной технике не работают правила типа "от перемены мест слагаемых сумма не изменяется", например операции "V / 100.0 * 3.0" и "V * 3.0 / 100.0" могут дать разные результаты.

P.S. И как узнать, что данные подготовлены правильно? С помощью аналогичных операций, которые в разных случаях дают разные результаты?.. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
Сергей Саныч
Мастер
Сообщения: 9116
Зарегистрирован: 30 май 2012, 14:20
Репутация: 2857
Откуда: Тюмень
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Сергей Саныч »

Serg писал(а): тождественные операции могут давать разные результаты, да ещё и зависящие от модели процессора.
Могут. Но обычно это скрыто за "толстым слоем компилятора". Даже сишный программист не имеет непосредственного доступа к флагам процессора. Не говоря о более высокоуровневых языках.
Serg писал(а): например операции "V / 100.0 * 3.0" и "V * 3.0 / 100.0" могут дать разные результаты
Ты бы еще спросил про i / 100 * 3 и i * 3 / 100 :)
А для FP разница проявится только в младших битах результата. Которые имеют значение разве что при сравнении на строгое равенство. Что для FP вообще не рекомендуется.
Serg писал(а): как узнать, что данные подготовлены правильно?
Подготовить их средствами, которые не могут дать неправильные данные :)
Чудес не бывает. Бывают фокусы.
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

Сергей Саныч писал(а): Могут. Но обычно это скрыто за "толстым слоем компилятора". Даже сишный программист не имеет непосредственного доступа к флагам процессора. Не говоря о более высокоуровневых языках.
Я ж выше писал что собой представляет язык C/C++. :) И любым хорошим программистам нужно как минимум изучить то, на чём будут компилиться и работать их программы и всякие errata, хотя-бы для того, что проверить есть в компиляторе соотв. "исправление" или надо их самому учитывать.
Да и не я начал сравнивать количество тактов в операциях. :)
Сергей Саныч писал(а): А для FP разница проявится только в младших битах результата.
При любых операциях с числами с плавающей точкой просто нужно помнить, что точное битовое представление существует лишь для бесконечно малого количества таких чисел.
Сергей Саныч писал(а): Подготовить их средствами, которые не могут дать неправильные данные
Т.е. система должна полностью автономна, ведь она не сможет доверять данным, приходящим из-вне - вдруг их там готовили не теми средствами... :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
X-Ray
Мастер
Сообщения: 597
Зарегистрирован: 04 фев 2016, 23:06
Репутация: 275
Настоящее имя: Дамир
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение X-Ray »

Тут есть тот кто поможет собрать и упаковать прогу с dll`ками в пакет под линуксом или ткнёт туда где копать читать.
Serg писал(а): И если после таких операций идёт if/while, то компилятор может создать на одну инструкцию больше или меньше.
Чтобы не годать вам сюда https://godbolt.org/
Программа GGEasy (фрезеровка из гербера, производство ПП на ЧПУ) GERBER_X3/releases
Прежде чем писать о багах проверьте, является ли ваша версия последней!
Баги - глюки и ПРЕДЛОЖЕНИЯ(Хотелки) писать СЮДА!!!
Багтрекер
Тестовая версия
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение Serg »

X-Ray писал(а): Тут есть тот кто поможет собрать и упаковать прогу с dll`ками в пакет под линуксом или ткнёт туда где копать читать.
В Linux нет .dll (Dynamic Link Librаry), в Linux .so - Shared Object (Code), т.е. единственный экземпляр этого объектного (скомпилированного) кода в памяти может одновременно использоваться несколькими приложениями. Можно начать с гугления "linux so".
X-Ray писал(а): Чтобы не годать вам сюда https://godbolt.org/
Нам ни годать, ни гадать не надо - у нас есть и компиляторы и отладчики. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
nkp
Мастер
Сообщения: 8340
Зарегистрирован: 28 ноя 2011, 00:25
Репутация: 1589
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение nkp »

вопрос по си:
вот есть в емс стандартный компонент :

Код: Выделить всё

/********************************************************************
* Description:  message.comp
*               Message HAL component.
*
* Author: Les Newell <les at sheetcam dot com>
* License: GPL Version 2 or later
*    
* Copyright (c) 2011 All rights reserved.
*
********************************************************************
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 or later of the GNU General
 * Public License as published by the Free Software Foundation.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
 * ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
 * TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
 * harming persons must have provisions for completely removing power
 * from all motors, etc, before persons enter any danger area.  All
 * machinery must be designed to comply with local and national safety
 * codes, and the authors of this software can not, and do not, take
 * any responsibility for such compliance.
 *
 * This code was written as part of the EMC HAL project.  For more
 * information, go to www.linuxcnc.org.
 *
*************************************************************************/
 
component message "Display a message";
 
description """Allows HAL pins to trigger a message. Example hal commands:
 loadrt message names=oillow,oilpressure,inverterfail messages="Slideway oil low,No oil
pressure,Spindle inverter fault"
 addf oillow servo-thread
 addf oilpressure servo-thread
 addf inverterfail servo-thread
 
 setp oillow.edge 0 #this pin should be active low
 
 net no-oil      classicladder.0.out-21 oillow.trigger
 net no-pressure classicladder.0.out-22 oilpressure.trigger
 net no-inverter classicladder.0.out-23 inverterfail.trigger
 
When any pin goes active, the corresponding message will be displayed.""";
 
pin in bit trigger =FALSE "signal that triggers the message";
pin in bit force =FALSE """A FALSE->TRUE transition forces the message to be
displayed again if the trigger is active""";
 
param rw bit edge =TRUE """Selects the desired edge: TRUE means falling, FALSE
means rising""";

modparam dummy messages """The messages to display. These should be listed,
comma-delimited, inside a single set of quotes. See the "Description" section
for an example.
If there are more messages than "count" or "names" then the excess will be
ignored. If there are fewer messages than "count" or "names" then an error will
be raised and the component will not load.""";
 
variable int myidx;
variable hal_bit_t prev_trigger = FALSE;
variable hal_bit_t prev_force = TRUE;
variable hal_bit_t prev_edge = TRUE;
 
option extra_setup yes;
 
function _ nofp "Display a message";
license "GPL v2";
;;
 
char *messages[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
RTAPI_MP_ARRAY_STRING(messages, 16, "Displayed strings");
 
FUNCTION(_){
    hal_bit_t show = false;    
    if(!!prev_edge != !!edge) /* edge type has changed */
    {
        prev_edge = edge;
        prev_trigger = !edge;
    }
    if(!!force != !!prev_force) /* force type has changed */
    {
        prev_force = force;
        if(force && (!!trigger == !!edge))
        {
            show = true;
        }
    }
    if(!!trigger != !!prev_trigger) /* trigger has changed */
    {
        prev_trigger = trigger;
        if(!!trigger == !!edge)
        {
            show = true;
        }
    }
    if(show && (messages[myidx] != 0))
    {
        rtapi_print_msg(RTAPI_MSG_ERR, "%s\n", messages[myidx]);
    }
}
 
EXTRA_SETUP(){
    myidx = extra_arg;
    if(myidx<0 || myidx >15)
    {
        rtapi_print_msg(RTAPI_MSG_ERR,"Count of names= is outside the allowable range 0..15\n");
        return -EINVAL;
    }
    if(messages[myidx] == 0)
    {
        rtapi_print_msg(RTAPI_MSG_ERR,"Message string for index %d missing\n", myidx);
        return -EINVAL;
    }
    return(0);
}
чем оправдано использование вот такого вида конструкций :
if(!!trigger != !!prev_trigger)

если !! не меняет логическое значение ,а проводит лишь некую "нормализацию" (но у нас пины bit ,
и по умолчанию не могут быть равны чему то иному ,чем 0 и 1 )

если приведение к bool , то опять же- пины у нас уже определены как bit
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

hal_bit_t обычно является typedef для целочисленного типа, диапазон которого больше, чем просто 0 и 1. При тестировании значения hal_bit_t никогда не сравнивайте его с 1.
Взято http://linuxcnc.org/docs/ja/html/man/ma ... .3hal.html отсюда.
nkp
Мастер
Сообщения: 8340
Зарегистрирован: 28 ноя 2011, 00:25
Репутация: 1589
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение nkp »

ok
и как эти переменные
variable hal_bit_t prev_trigger = FALSE;
variable hal_bit_t prev_force = TRUE;
variable hal_bit_t prev_edge = TRUE
в компоненте могут поиметь значения
отличные от 0 или 1 ?
даже не так - (не) будет ли работать :
force != prev_force
вместо
!!force != !!prev_force
Аватара пользователя
uralpt
Мастер
Сообщения: 651
Зарегистрирован: 23 ноя 2015, 14:31
Репутация: 104
Настоящее имя: евгений
Откуда: Миасс
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение uralpt »

Под TRUE может скрываться любое значение.

Хотя, возможны варианты -
1. Возможно, реальное численное значение trigger ему еще зачем-то нужно. (вряд ли)
2. Двойное логическое преобразование на всеми входящими данными (!!trigger) делается, чтобы в дальнейшем избежать возможных проблем, которые могут вылезти на другом участке кода.
3. Это шаблон. Работая в команде, программисты договорились, что не будут искажать оригиналы переменных, что бы в них ни было. В своем, локальном участке кода - пожалуйста.
4. Привычка :))
nkp писал(а): даже не так - (не) будет ли работать :
force != prev_force
вместо
!!force != !!prev_force
if... < 0 > точно будет.
Если есть уверенность, что в переменных только 0 или 1, тоже будет. Ну а вдруг там окажется значение >1?
Вариантов, как это написать, много. Но чисто зрительно, увидев "!!", сразу понимаешь, что имеешь дело с логическим типом данных.
Аватара пользователя
MX_Master
Мастер
Сообщения: 7465
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3088
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение MX_Master »

Для этого сравнения достаточно и

if(!trigger != !prev_trigger)

Но, возможно, компилятор это оптимизирует и сам.
nkp
Мастер
Сообщения: 8340
Зарегистрирован: 28 ноя 2011, 00:25
Репутация: 1589
Контактная информация:

Re: Программистские задачки и хитрости

Сообщение nkp »

Тоже склоняюсь к п.4
Ответить

Вернуться в «Оффтоп»