Страница 8 из 9

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

Добавлено: 13 мар 2021, 20:50
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...

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

Добавлено: 13 мар 2021, 21:19
Сергей Саныч
Чтобы было понятней и компилятору и себе, а также исключить возможные разночтения, я бы так сделал:

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

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

w = ((uint32_t)mess[0] << 8) + (uint32_t)mess[1];
Типы и их преобразования прописаны в явном виде. Также в явном виде обозначен сдвиг на 8 разрядов, вместо умножения на 256.
Компилятор, скорее всего, сам бы вписал сдвиг вместо умножения, но так для себя понятнее.

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

Добавлено: 13 мар 2021, 21:26
MX_Master
А вместо сложения компилятор подставит побитовое ИЛИ?

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

Добавлено: 13 мар 2021, 22:04
uralpt
Duhas писал(а):

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

unsigned long w;  //почему такой тип?
Этот тип выдернут из тела программы, не стал исправлять. Изначально код делался для самописанной функции хеширования, это значение целиком вмещает хеш. Все на примитивном уровне, но для бытового секретика при никому неизвестном алгоритме - вполне себе.
В любом случае, решение с uint_t более правильно. Буду заново переписывать.
Не ожидал я такой подставы от char :))

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

Добавлено: 14 мар 2021, 01:13
Serg
MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
gcc при "-O2" скорее всего всю эту строчку в две инструкции пересылки превратит. В принципе можно и самому так написать, но это будет ненаглядно.
uralpt писал(а): Не ожидал я такой подставы от char :))
В gcc и некоторых других компиляторах есть флаг, делающий char по умолчанию unsigned.

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

Добавлено: 14 мар 2021, 11:47
Сергей Саныч
MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
Нет смысла. Обе операции простые, выполняются за одинаковое количество тактов. В отличие от умножения, которое не факт, что выполняется так же быстро.

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

Добавлено: 14 мар 2021, 12:57
Duhas
Сергей Саныч писал(а): 14 мар 2021, 11:47
MX_Master писал(а): А вместо сложения компилятор подставит побитовое ИЛИ?
Нет смысла.
не соглашусь, во-первых, ИЛИ точнее описывает смысл выполняемых действий, во-вторых, если окажутся вдруг ненулевые биты в неположенных местах искажение данных будет выше со сложением, хотя это уже за уши тяну..

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

Добавлено: 14 мар 2021, 15:20
Serg
Основное различие - это какие биты регистра статуса могут изменится в результате операции. Например ИЛИ никогда не вызовет переполнения.
Так-же операция 0 | (int8_t)(-128) на многих процессорах с разрядностью более 8 бит не вызовет установки бита отрицательного результата, а операция 0 + (int8_t)(-128) вызовет.
И если после таких операций идёт if/while, то компилятор может создать на одну инструкцию больше или меньше.

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

Добавлено: 14 мар 2021, 21:42
Сергей Саныч
Serg писал(а): Основное различие - это какие биты регистра статуса могут изменится в результате операции. Например ИЛИ никогда не вызовет переполнения.
В данном конкретном случае ни переполнения, ни переноса возникнуть не может ни при ИЛИ, ни при сложении. Если исходные данные подготовлены правильно, ситуация 1+1 не возникнет ни в одном разряде.

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

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

P.S. И как узнать, что данные подготовлены правильно? С помощью аналогичных операций, которые в разных случаях дают разные результаты?.. :)

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

Добавлено: 15 мар 2021, 07:00
Сергей Саныч
Serg писал(а): тождественные операции могут давать разные результаты, да ещё и зависящие от модели процессора.
Могут. Но обычно это скрыто за "толстым слоем компилятора". Даже сишный программист не имеет непосредственного доступа к флагам процессора. Не говоря о более высокоуровневых языках.
Serg писал(а): например операции "V / 100.0 * 3.0" и "V * 3.0 / 100.0" могут дать разные результаты
Ты бы еще спросил про i / 100 * 3 и i * 3 / 100 :)
А для FP разница проявится только в младших битах результата. Которые имеют значение разве что при сравнении на строгое равенство. Что для FP вообще не рекомендуется.
Serg писал(а): как узнать, что данные подготовлены правильно?
Подготовить их средствами, которые не могут дать неправильные данные :)

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

Добавлено: 15 мар 2021, 15:11
Serg
Сергей Саныч писал(а): Могут. Но обычно это скрыто за "толстым слоем компилятора". Даже сишный программист не имеет непосредственного доступа к флагам процессора. Не говоря о более высокоуровневых языках.
Я ж выше писал что собой представляет язык C/C++. :) И любым хорошим программистам нужно как минимум изучить то, на чём будут компилиться и работать их программы и всякие errata, хотя-бы для того, что проверить есть в компиляторе соотв. "исправление" или надо их самому учитывать.
Да и не я начал сравнивать количество тактов в операциях. :)
Сергей Саныч писал(а): А для FP разница проявится только в младших битах результата.
При любых операциях с числами с плавающей точкой просто нужно помнить, что точное битовое представление существует лишь для бесконечно малого количества таких чисел.
Сергей Саныч писал(а): Подготовить их средствами, которые не могут дать неправильные данные
Т.е. система должна полностью автономна, ведь она не сможет доверять данным, приходящим из-вне - вдруг их там готовили не теми средствами... :)

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

Добавлено: 17 мар 2021, 14:15
X-Ray
Тут есть тот кто поможет собрать и упаковать прогу с dll`ками в пакет под линуксом или ткнёт туда где копать читать.
Serg писал(а): И если после таких операций идёт if/while, то компилятор может создать на одну инструкцию больше или меньше.
Чтобы не годать вам сюда https://godbolt.org/

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

Добавлено: 17 мар 2021, 17:12
Serg
X-Ray писал(а): Тут есть тот кто поможет собрать и упаковать прогу с dll`ками в пакет под линуксом или ткнёт туда где копать читать.
В Linux нет .dll (Dynamic Link Librаry), в Linux .so - Shared Object (Code), т.е. единственный экземпляр этого объектного (скомпилированного) кода в памяти может одновременно использоваться несколькими приложениями. Можно начать с гугления "linux so".
X-Ray писал(а): Чтобы не годать вам сюда https://godbolt.org/
Нам ни годать, ни гадать не надо - у нас есть и компиляторы и отладчики. :)

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

Добавлено: 22 июн 2021, 10:14
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

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

Добавлено: 22 июн 2021, 11:51
uralpt
hal_bit_t обычно является typedef для целочисленного типа, диапазон которого больше, чем просто 0 и 1. При тестировании значения hal_bit_t никогда не сравнивайте его с 1.
Взято http://linuxcnc.org/docs/ja/html/man/ma ... .3hal.html отсюда.

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

Добавлено: 22 июн 2021, 11:59
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

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

Добавлено: 22 июн 2021, 12:20
uralpt
Под TRUE может скрываться любое значение.

Хотя, возможны варианты -
1. Возможно, реальное численное значение trigger ему еще зачем-то нужно. (вряд ли)
2. Двойное логическое преобразование на всеми входящими данными (!!trigger) делается, чтобы в дальнейшем избежать возможных проблем, которые могут вылезти на другом участке кода.
3. Это шаблон. Работая в команде, программисты договорились, что не будут искажать оригиналы переменных, что бы в них ни было. В своем, локальном участке кода - пожалуйста.
4. Привычка :))
nkp писал(а): даже не так - (не) будет ли работать :
force != prev_force
вместо
!!force != !!prev_force
if... < 0 > точно будет.
Если есть уверенность, что в переменных только 0 или 1, тоже будет. Ну а вдруг там окажется значение >1?
Вариантов, как это написать, много. Но чисто зрительно, увидев "!!", сразу понимаешь, что имеешь дело с логическим типом данных.

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

Добавлено: 22 июн 2021, 13:16
MX_Master
Для этого сравнения достаточно и

if(!trigger != !prev_trigger)

Но, возможно, компилятор это оптимизирует и сам.

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

Добавлено: 22 июн 2021, 17:05
nkp
Тоже склоняюсь к п.4