Низкоуровневое программирование на C++ (Помогите найти ответы...)

Модератор: Модераторы разделов

godima
Сообщения: 92
ОС: Debian Etch

Низкоуровневое программирование на C++

Сообщение godima »

Добрый день!
У меня вот какой вопрос...
Мне нужно написать максимально быструю программу по работе с большими массивами целочисленных и плавающих данных...
Вчера тут открывал тему про разделение программы на несколько файлов ("3 вопроса по C++" называлась), там идет речь про БПФ.
Программа взята из книжки, реализована достаточно интересно, там используются интенсивно низкоуровневые операции. У меня в программе
считаются мат. ожидание, СКО, ну и еще всякая всячина... Вопрос в том, где можно почитать, как именно с помощью операций сдвига можно посчитать,
например, СКО, ну или хоть что, желательно с примерами. Т.е. где подробно описывается работа с низкоуровневыми операциями. Можно книжку, или статьи
в Интернет, на рус, англ, без разницы.
Еще вот какой вопрос, можно ли в C++ работать с отдельными битами, например, имеем число типа int, в котором записано десятичное число 7.
Как я понимаю, оно в представлении компа будет выглядеть как 0000 0000 0000 0111. Я вот хочу сделать из него 0000 0010 0000 0111. Т.е. я должен
сделать в программе
int a = 512 | 7;
а можно попроще? :) или только так. пишем на бумажке 2-чное число, смотрим, какие биты хотим поменять, выбираем тип операции, другое 2-чное число,
потом их оба в 10-чную сист.счисл. перегоняем, или в 16-ричную и фигачим в программе...

И еще вопрос :)
Вот есть у меня 2 числа по 1-му байту (unsigned char) хочу из них слепить одно число типа int. Ну или 4 числа по 1-му байту, хочу слепить тип long.
Это вообще делается, если да, то как. Обратная задача тоже интересна...

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

Заранее спасибо за помощь.
Спасибо сказали:
Аватара пользователя
Uncle_Theodore
Сообщения: 3339
ОС: Slackware 12.2, ArchLinux 64

Re: Низкоуровневое программирование на C++

Сообщение Uncle_Theodore »

godima писал(а):
04.10.2007 07:43
И еще вопрос :)
Вот есть у меня 2 числа по 1-му байту (unsigned char) хочу из них слепить одно число типа int. Ну или 4 числа по 1-му байту, хочу слепить тип long.
Это вообще делается, если да, то как.

Нуууу.... совсем так не выйдет, конечно... Но вот, поразвлекайся.

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

#include<iostream>
using namespace std;

int main()
{
  cout << "size of " << endl;
  cout << "\t unsigned char is " << sizeof(unsigned char) << endl;
  cout << "\t int is " << sizeof(int) << endl;
  cout << "\t long is " << sizeof(long) << endl;

  unsigned char bb[4] = {2,1,0,0};
  int mint = *(int*)bb;
  long shmong = *(long*)bb;

  cout << "mint = " << mint << endl;
  cout << "shmong = " << shmong << endl;

  return 0;
}
Спасибо сказали:
godima
Сообщения: 92
ОС: Debian Etch

Re: Низкоуровневое программирование на C++

Сообщение godima »

Uncle_Theodore писал(а):
04.10.2007 08:37
godima писал(а):
04.10.2007 07:43
И еще вопрос :)
Вот есть у меня 2 числа по 1-му байту (unsigned char) хочу из них слепить одно число типа int. Ну или 4 числа по 1-му байту, хочу слепить тип long.
Это вообще делается, если да, то как.

Нуууу.... совсем так не выйдет, конечно... Но вот, поразвлекайся.

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

#include<iostream>
using namespace std;

int main()
{
  cout << "size of " << endl;
  cout << "\t unsigned char is " << sizeof(unsigned char) << endl;
  cout << "\t int is " << sizeof(int) << endl;
  cout << "\t long is " << sizeof(long) << endl;

  unsigned char bb[4] = {2,1,0,0};
  int mint = *(int*)bb;
  long shmong = *(long*)bb;

  cout << "mint = " << mint << endl;
  cout << "shmong = " << shmong << endl;

  return 0;
}



Спасибо, идею понял, а обратную задачу, т.е. из числа long сделать 4 числа unsigned char можно?
Спасибо сказали:
Аватара пользователя
minoru-kun
Сообщения: 621
ОС: Debian GNU/Linux

Re: Низкоуровневое программирование на C++

Сообщение minoru-kun »

ОМГ...
Вот есть у меня 2 числа по 1-му байту (unsigned char) хочу из них слепить одно число типа int

Самый простой и понятный способ: int x = младший_байт + старший_байт*2^8
а обратную задачу, т.е. из числа long сделать 4 числа unsigned char можно?

Можно просто совмещать с маской, а далее сдвигать на нужное число битов вправо:
char byte1 = (long a && 0xFF000000) / 2^(8*3)
char byte2 = (long a && 0x00FF0000) / 2^(8*2)
char byte3 = (long a && 0x0000FF00) / 2^(8*1)
char byte4 = long a && 0x000000FF
где || - знак логической побитовой дизъюкции.
Нет времени проверять решение, но теоретически, вроде бы, правильно. ^_^ Брать абсолютный адрес указателя, прибавлять size(char)*нужный_номер и присваивать переменной вместе с операцией приведения типа, конечно, проще, но некошерно, ибо может привести к нарушению кроссплатформенности.
p.s. нашел одну жуткую ошибку по невнимательности, отредактировал.
Спасибо сказали:
Аватара пользователя
Red Gremlin
Сообщения: 512
Статус: самоучка
ОС: Rosa 2016 Fresh

Re: Низкоуровневое программирование на C++

Сообщение Red Gremlin »

char -> int16
int16a = (chara<<8)+charb;

int16 -> int32
longa=(int16a<<16)+int16b;

char -> int32
longa=(chara<<24)+(charb<<16)+(charc<<8)+chard;

int16 -> char
chara=(int16a>>8);
charb=(int16a && 0xff);

и так далее ...
P.S. А еще есть LE и BE ...
"В мире есть случайность, есть предопределенность и есть то, что ты планируешь совершить."
Спасибо сказали:
godima
Сообщения: 92
ОС: Debian Etch

Re: Низкоуровневое программирование на C++

Сообщение godima »

Спасибо за ответы...
только вот никто так и не сказал, где можно почитать про всякие сдвиги, их использование и логические операции... т.е. как это можно ниучиться эффективно использовать...
Спасибо сказали:
Аватара пользователя
minoru-kun
Сообщения: 621
ОС: Debian GNU/Linux

Re: Низкоуровневое программирование на C++

Сообщение minoru-kun »

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

Вам срочно нужна книжка + хорошая практика по Асму. + Справочник команд архитектуры i386 в качестве живого примера. + Побольше прикладной математики. :)

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

chara=(int16a>>8);
charb=(int16a && 0xff);

Может, тогда уж

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

chara=(int16a && 0xff00) >> 8;
charb=(int16a && 0xff);

?
Кстати, немного смущает, что по идее, в chara получится младший, а в charb - соответственно, старший байт на привычной нам little-endian, но наоборот - на big-endian (на СПАРКах, например) архитектуре... Может, в условиях данной задачи и не сильно принципиально, но все равно... :/
Спасибо сказали:
Аватара пользователя
Attila
Сообщения: 125
Статус: Тролль-Лѣсовичокъ
ОС: Свободная aka ArchLinux

Re: Низкоуровневое программирование на C++

Сообщение Attila »

Можно ещё для превращения int'ов в char'ы и наоборот использовать union'ы.

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

union u_type {
int i;
char c[4];
};


i и c находятся в одной и той же памяти, и это можно использовать для преобразования четырёх байтов в int и обратно.

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

char a, b, c, d;
int i;
...
union u_type u;
u.c[0] = a;
u.c[1] = b;
u.c[2] = c;
u.c[3] = d;
i = u.i;

Фактически, это почти то же самое, что в примере Uncle_Theodore
Спасибо сказали:
Аватара пользователя
Red User
Сообщения: 229
ОС: Debian

Re: Низкоуровневое программирование на C++

Сообщение Red User »

Есть ещё такая штука как поля битов:

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

#include <cstdio>

int main()
{
    union {
        int num;
        struct {
            unsigned p1: 4;
            unsigned p2: 4;
            unsigned p3: 4;
            unsigned p4: 4;
            unsigned p5: 4;
            unsigned p6: 4;
            unsigned p7: 4;
            unsigned p8: 4;
        };
    } chnum;

    chnum.num = 0;
    chnum.p1 = 0xa;
    chnum.p8 = 0xb;

    printf("%x\n", chnum.num);

    return 0;
}
А ведь когда-то не боялись мы программы любой,
И с одним лишь debug'ом выходили на бой,
И искусно написанный вирус встречали как брата
Спасибо сказали:
beep_boop
Сообщения: 3
ОС: Linux

Re: Низкоуровневое программирование на C++

Сообщение beep_boop »

godima писал(а):
04.10.2007 16:46
Спасибо за ответы...
только вот никто так и не сказал, где можно почитать про всякие сдвиги, их использование и логические операции... т.е. как это можно ниучиться эффективно использовать...

В книге Зубков С.В. "Ассемблер для DOS, Windows и Unix" главы 8 и 9 - то, что ты ищешь. ;)
Slackware 12.0
Спасибо сказали:
Аватара пользователя
minoru-kun
Сообщения: 621
ОС: Debian GNU/Linux

Re: Низкоуровневое программирование на C++

Сообщение minoru-kun »

Можно ещё для превращения int'ов в char'ы и наоборот использовать union'ы.

Какое простое и элегантное решение... :)
Спасибо сказали:
Аватара пользователя
Red Gremlin
Сообщения: 512
Статус: самоучка
ОС: Rosa 2016 Fresh

Re: Низкоуровневое программирование на C++

Сообщение Red Gremlin »

minoru-kun писал(а):
04.10.2007 18:08
Может, тогда уж

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

chara=(int16a && 0xff00) >> 8;
charb=(int16a && 0xff);

Зачем писать лишние символы?
Кстати, немного смущает, что по идее, в chara получится младший, а в charb - соответственно, старший байт

Наоборот.
"В мире есть случайность, есть предопределенность и есть то, что ты планируешь совершить."
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Низкоуровневое программирование на C++

Сообщение sergio »

minoru-kun писал(а):
04.10.2007 18:08
Может, тогда уж

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

chara=(int16a && 0xff00) >> 8;
charb=(int16a && 0xff);

Зачем писать лишние символы?

Поддерживаю. Лишние символы убрать:
Во-первых
(int16a & 0xff00) >> 8
Во-вторых
int16a >> 8 & 0x00FF
В-третьих битовые операции желательно делать на unsigned.

По существу вопроса все варианты вроде уже назвали: сдвиги, юнион, битовые поля.
Имеем в виду, что все размеры типов зависят от платформы, битовые операции не всегда переносимы а извлечения одних типов из других и обратно - зачастую непереносимо. Т.е. все базовые операции надо выделять по уму в отдельные функции-макросы, typedef-ить типы и проч... (если нужен "правильный код", а не просто чтоб заработало...)
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
godima
Сообщения: 92
ОС: Debian Etch

Re: Низкоуровневое программирование на C++

Сообщение godima »

Red User писал(а):
04.10.2007 19:19
Есть ещё такая штука как поля битов:

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

#include <cstdio>

int main()
{
    union {
        int num;
        struct {
            unsigned p1: 4;
            unsigned p2: 4;
            unsigned p3: 4;
            unsigned p4: 4;
            unsigned p5: 4;
            unsigned p6: 4;
            unsigned p7: 4;
            unsigned p8: 4;
        };
    } chnum;

    chnum.num = 0;
    chnum.p1 = 0xa;
    chnum.p8 = 0xb;

    printf("%x\n", chnum.num);

    return 0;
}



Это понятно, что такая штука есть, но на сколько пишет Шилдт, это не слишком быстро и иногда не переносимо...
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Низкоуровневое программирование на C++

Сообщение sergio »

godima писал(а):
05.10.2007 14:56
Это понятно, что такая штука есть, но на сколько пишет Шилдт, это не слишком быстро и иногда не переносимо...

"Быстро" - понятие относительное. :happy: Причем да/нет сравнивать надо не со скорость света в вакууме, а с альтернативными решениями. Что об этом пишет Шилдт?
Возня с битами всегда менее переносима, чем интеджеры. Но и с инт можно получить непереносимый код, если переедете на платформу с 16бит инт, а вашему коду нужно больше чем 32767... (Да, и тут все те же биты. =) )
Так что опять же надо уточнять у Шилдта, в каких случаях и куда непереносимо...
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали: