Страницы

Поиск по вопросам

Показаны сообщения с ярлыком c++. Показать все сообщения
Показаны сообщения с ярлыком c++. Показать все сообщения

среда, 15 апреля 2020 г.

Размер стека во встраиваемых ОС реального времени (FreeRTOS, OpenRtos)

#c #freertos

                    
Пытаюсь использовать FreeRTOS в проекте (проц - avr32). Заметил такую штуку. Если
увеличить размер стека для задачи, прошивка тупо виснет. В дизасме пустой бесконечный
цикл. Если сделать размер стека задачи маленьким, виснет сама задача. Кто знает, как
правильно выбрать размер стека в принципе и какие причины сей проблемы могут быть кроме
размера стека?    


Ответы

Ответ 1



Виснуть может по простой причине - процессор просто не может выделить сколько места под стек. Пусть у Вас всего 32кб памяти, а под стек выделяете 64кб - понятно, что будут пробемы:) С другой стороны, 16кб может быть нормально, но в памяти не только стек размещается... Но обычно стек больше половины доступной оперативки не должен быть. Также, нужно помнить, что эти процессоры очень привередливы. Например, размер стека должен быть кратным 4кб. Иначе виснет. Все это лучше читать в документации на процессор. И ещё одна причина подвисания прошивок, с которой я стыкался. У некоторых процессоров flash для прошивки не монолитный, а составной, например 8+8+16+32кб, то есть, 4 блока разного размера. И если какая то процедура попадает на стык - могут быть проблемы. А если ещё код выполняет близкий переход через границу - так подвисает на ура. Решалось анализом кода и составленим правильно мап файла для распределения процедур по блокам.

Как передать звук с микрофона по сети?

#c_sharp #c #delphi #cpp

                    
Нужно передать звук с микрофона по сети на другой комп и воспроизвести там. Я знаю,
что мне нужна 2 программы. Сервер и Клиент. А еще я знаю, что я дожна использовать
RTP. Я справилась с задачей c помощью FTP.  Думала, что и с этой справлюсь, но что-то
не получается. Прошу помощь. Спасибо всем заранее.    


Ответы

Ответ 1



По хорошему суть такова: берем поток с микрофона, режем на кусочки по 0.1-0.5 сек (смотря насколько вам нужен реалтайм, чем выше частота, тем больше нагрузка). Кодируем сей кусочек в mp3 и шлем по уже созданному сокет-соединению. Там, соотв-но, дешифруем и воспроизводим. Собственно, если вас не сильно заботит траффик, можно решать в лоб(без перекодировки, в PCM MONO). В который раз тут пиарю либу, уж простите) Чего делаем: инициализируемся, определяем девайс микрофона. Выставляем потоку глубину/частоту, чтобы ваше соединение вытянуло (ширина потока будет = (глубинаbps / 8) * 1 канал(моно) * частотадискретизации байт/сек). Далее: открываем соединение с клиентом и раз в 0.1-0.5 сек берем с потока байты и шлем в сокет. С такой же частотой на клиенте считываем данные с сервера и напрямую воспроизводим. Отправку/прием лучше реализовать в отдельном потоке. В архиве для дельфей (скорее всего не только, но не проверял) куча примеров, которые можно расковырять. В т.ч. был пример с инет-радио. В том же архиве хелп по всем функциям, наложить их на алгоритм выше не должно быть проблемой.

Преобразование шрифта в массив

#c #шрифты #embedded

                    
Посоветуйте, пожалуйста, утилиты (доступные для скачивания) для преобразования шрифта
в заголовочный файл *.h с массивом, содержащим растр для всех нужных символов для использования
во встраиваемых системах.
Типа такого: Freescale Embedded GUI Converter Utility 2.0 (судя по всему, его так
просто не скачать).    


Ответы

Ответ 1



Нашел ответ на stackoverflow. Предлагается использовать утилиту convert из imagemagick. Например команда: convert -resize 7x13\! -font /Library/Fonts/Arial.ttf -pointsize 10 label:A A.xbm генерирует побитовое представление буквы A: #define A_width 7 #define A_height 13 static char A_bits[] = { 0x00, 0x00, 0x04, 0x0C, 0x0A, 0x0A, 0x1E, 0x1F, 0x11, 0x11, 0x00, 0x00, 0x00, };

понедельник, 13 апреля 2020 г.

CUDA: Ошибка при компиляции программы

#c #cuda #cpp

                    
Доброго времени суток!
Прошу помочь. Компиляция программы не проходит из-за ошибок типа "identifier is undefined
in device code".  Пояснение по программе: есть реализация AES от Брайена Гладмана (Brian
Gladman, Worcester, UK), которую я хочу использовать в своей cuda-программе.  Ошибка,
мешающая компиляции, возникает при использовании макроса в коде Брайена. Например,
в строчке:
ke8(cx->ks, 0); ke8(cx->ks, 1);

ke8 - это макрос, его код:
#define ke8(k,i) \
{ kef8(k,i); \
    k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \
    k[8*(i)+13] = ss[5] ^= ss[4]; \
    k[8*(i)+14] = ss[6] ^= ss[5]; \
    k[8*(i)+15] = ss[7] ^= ss[6]; \
}

Насколько я понял, такая ошибка связана с макросами, и во время компиляции он не
определяется cuda-устройством. Хотя, буквально 2-мя строчками выше "ke8(cx->ks, i);"
работает без нареканий, а ведь там тоже работает тот же самый макрос. Гугль-поиск решения
этой проблемы не дал.
Из-за чего может возникать ошибка "identifier is undefined in device code", и как
её решить?    


Ответы

Ответ 1



Ошибка identifier is undefined in device code возникает в том случае, если идентификатор не определен. Поскольку, глядя на макрос, трудно сказать, во что он раскрывается, рекомендуется посмотреть на файл, полученный из исходника препроцессором. Для этого в C/C++/Preprocessor, выставить Generate Preprocessed File в YES. После компиляции посмотреть на код, оставшийся от макроса, и обратить внимание на те переменные, которые трактуются как необъявленные. Если их реально нет, значит, что-то не подключено (библиотека или заголовок).

Ответ 2



Вам нужно добавить директиву препроцессора GPU, в противном случае фиксированные поисковые таблици не определены в памяти устройства, а в памяти хоста и CUDA не может их найти.

Как программно измененить громкость звука в Windows?

#c #windows #winapi #windows_7 #аудио

                    
Как программно измененить громкость звука в Windows?

Можете написать пример?
Желательно, чтобы скомпилился  на minGW.  
    


Ответы

Ответ 1



Нашел хороший пример на MSDN: How to Use Wave Audio Volume Control APIs, есть как получение громкости, так и установка. Данный пример дает нужный результат на версиях WIndows ниже Vista. В Windows Vista и 7 были представлены новые API для работы с аудио, для изменения громкости глобально нужно использовать интерфейс IAudioEndpointVolume. Небольшой пример использования есть также в MSDN и на CodeProject:

Ответ 2



Анимированое изменение звука системы Win7 C++ visual studio 10 #include #include #include #pragma comment(lib, "ole32.lib") //extern bool ChangeVolume(double nVolume,bool bScalar) { HRESULT hr=NULL; bool decibels = false; bool scalar = false; double newVolume=nVolume; CoInitialize(NULL); IMMDeviceEnumerator *deviceEnumerator = NULL; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator); IMMDevice *defaultDevice = NULL; hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice); deviceEnumerator->Release(); deviceEnumerator = NULL; IAudioEndpointVolume *endpointVolume = NULL; hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume); defaultDevice->Release(); defaultDevice = NULL; // ------------------------- float currentVolume = 0; endpointVolume->GetMasterVolumeLevel(¤tVolume); //printf("Current volume in dB is: %f\n", currentVolume); hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume); //CString strCur=L""; //strCur.Format(L"%f",currentVolume); //AfxMessageBox(strCur); // printf("Current volume as a scalar is: %f\n", currentVolume); if (bScalar==false) { hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL); } else if (bScalar==true) { hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL); } endpointVolume->Release(); CoUninitialize(); return FALSE; } float i = 0; int main() { float volume = 0; while(1) { i+=0.01; volume = (sin(i)+1)/2; ChangeVolume(volume,1); std::cout< #include #include #pragma comment(lib, "ole32.lib") //extern //Управление звуком class VolumeOS { public: HRESULT hr; bool decibels; bool scalar; double Volume; VolumeOS() { hr=NULL; decibels = false; scalar = false; CoInitialize(NULL); //newVolume=nVolume; } bool VolumeSET(double nVolume,bool bScalar) { double newVolume = nVolume; Volume = newVolume; IMMDeviceEnumerator *deviceEnumerator = NULL; hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator); IMMDevice *defaultDevice = NULL; hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice); deviceEnumerator->Release(); deviceEnumerator = NULL; IAudioEndpointVolume *endpointVolume = NULL; hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume); defaultDevice->Release(); defaultDevice = NULL; // ------------------------- float currentVolume = 0; endpointVolume->GetMasterVolumeLevel(¤tVolume); //printf("Current volume in dB is: %f\n", currentVolume); hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume); //CString strCur=L""; //strCur.Format(L"%f",currentVolume); //AfxMessageBox(strCur); // printf("Current volume as a scalar is: %f\n", currentVolume); if (bScalar==false) { hr = endpointVolume->SetMasterVolumeLevel((float)newVolume, NULL); } else if (bScalar==true) { hr = endpointVolume->SetMasterVolumeLevelScalar((float)newVolume, NULL); } endpointVolume->Release(); return FALSE; } ~VolumeOS() { CoUninitialize(); } }; float i = 0; int main() { VolumeOS A; float volume = 0; while(1) { i+=0.01; volume = (sin(i)+1)/2; A.VolumeSET(volume,true); std::cout<

Функция fread: остановится ли считывание при наличиии \0?

#c #файлы #функции

                    
Здравстdуйте! Допустим у нас есть файл. Мы его открыли, а потом считываем оттуда
информацию с помощью fread. Вопрос: а если в файле есть \0, то fread остановится считывать
информацию на \0 или будет дальше считывать информацию до конца файла.    


Ответы

Ответ 1



Вопрос на самом деле не дурацкий :-) Вообще - чтение файла ф-цией fread не заканчивается при достижении какого-либо символа, только лишь при ошибках ввода-вывода или если файл закончился. Посмотреть описание ф-ции можно в справочниках. Например, здесь или здесь

Использование C или С++ ? [закрыт]

#c #cpp

                            
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
            
                    
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 4 года назад.
                    
                
        

Изучаю "Си" недавно, после Java начал, сам язык очень понравился, минимум абстракций,
очень простой и сложный одновременно. Вопрос в том что не вижу грани когда нужно использовать
Си, а когда С++, "плюсы" я не знаю и представляю их себе как чистый "Си" только с прекрученным
ООП и возникает вопрос: смысл использовать С++ если тоже можно написать на "Си" и он
однозначно проще плюсов ?! Просто вакансии в основном на С++ вот и решил задать вопрос
типа а как же Си, если везде используют "плюсы" ...     
    


Ответы

Ответ 1



Все очень просто - использовать C++ там, где это возможно. Где необходимо (низкий уровень, взаимодействие с API) можно опускаться к C-подмножеству (оставаясь в рамках синтаксиса C++). Писать на чистом C же есть смысл там, где такие жертвы окупятся, а этих областей не много: системное программирование (специфика Linux), да программировании контроллеров (ресурсы крайне ограничены).

суббота, 11 апреля 2020 г.

Отключение 3,3v

#c #arduino

                    
Можно ли программно отключить питание (на время, а потом снова подать) на ножке 3,3v.
Тем самым сделать ресет всем периферийным устройствам питающимся с этой ножки.
    


Ответы

Ответ 1



Чтобы сбросить подключенные модули (например, шилды), потребуется добавить цепь холодного сброса. С её помощью можно будет "нажимать кнопку сброса", устанавливая в логическую 1 один из выводов микроконтроллера. Вопрос лишь в том, что микроконтроллер ATmega управляется инверсным сигналом NRESET. То есть при логическом 0 микроконтроллер находится в состоянии сброса. То есть сигнал сброса нужно инвертировать. Чтобы реализовать эту логику, потребуется 1 транзистор и 1 резистор. Схему и пример скетча см. здесь.

Ответ 2



Попробуйте реализовать программную перезагрузку Arduino c помощью функции reset, если в вашем случае можно позволить себе перезагружать и отрабатывать скетч заново.

Как последовательно запустить несколько процессов, а код завершения последнего потомка передать первому процессу?

#c #linux

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

Создал в цикле 5 процессов:

pid_t return_value;

  for(int i = 0; i < 5; i++)
  {
    return_value = fork();
    printf("%s %d %s %d\n", "Процесс: ", getpid(), "PID: ", return_value);  
  }

  return 0;


Данный код выдает мне в терминале огромную простыню, 


Я так понимаю что это из-за того, что после создания нового процесса они продолжают
выполняться параллельно. Как код завершения последнего потомка передать первому процессу
так и не выяснил. Подскажите как правильно сделать? 
    


Ответы

Ответ 1



Надеюсь, Вы уже сами успешно решили свою задачку, но на всякий случай вот простой код. #include #include #include #include int main (int ac, char *av[]) { int n = 5, s; srand(getpid()); while (n--) if (fork()) break; if (n < 0) { // last child s = rand() % 100; printf("child %d exit rc: %d\n", (int)getpid(), s); exit(s); } wait(&s); if (n != 4) // all except first exit(WEXITSTATUS(s)); printf("Grandfather %d: child exited: %d\n", (int)getpid(), WEXITSTATUS(s)); return puts("End") == EOF; } Т.е. делаем цикл по переменной (в коде -- n), которая наследуется новым процессом и в нем запускаем новый процесс. Родитель выходит из цикла, ждет завершения потомка (тот в свою очередь ждет завершения своего потомка и так 5 раз). Если это не прародитель (определяем по n), то выходим с кодом завершения потомка, который получили в wait(). (без pipe передать PID последнего процесса в первый не получится (конечно, кроме разделяемой памяти или файла), но это мы с Вами вроде уже обсуждали).

Функция вызывается с неправильными значениями переменных

#cpp #c #fft #обработка_сигналов

                    
Суть вопроса такова. Есть такой код:

#include "stdafx.h"

#define PI 3.1415926535897932384626433832795
#define FR 3
#define SAMPLES 1024

int _tmain(int argc, _TCHAR* argv[])
{
   base signal[SAMPLES];

   for (int i = 0; i < SAMPLES; ++i)
   {
       signal[i] = (sin(2*PI*i*FR), 0);
   }

   FFTCalculate(signal, SAMPLES, false);

   FILE* f_pointer = fopen("fft_result.txt", "w");

   for (int i = 0; i < SAMPLES; ++i)
   {
       char num = (char)signal[i].real();
       int out = fprintf(f_pointer, &num);
   }
   int out = fclose(f_pointer);
   return 0;
}


в нем вызывается функция FFTCalculate(signal, SAMPLES, false). Ниже приведен код функции:

void FFTCalculate(base signal[], int n, bool invert)
{   
int log_N;
double x = frexp((double)n, &log_N);

   calc_rev(n, log_N);

   for(int i = 0; i < n; ++i)
       if (i < rev[i])
               swap(signal[i], signal[rev[i]]);

   for(int len = 2; len <= n; len<<=1)
   {
       double ang = 2*PI/len * (invert?-1:1);
       int len2   = len>>1;

       base wlen (cos(ang), sin(ang));
       wlen_pw[0] = base(1, 0);
       for (int i=0; i


Ответы

Ответ 1



Я проверил на GCC 4.8.2 под linux. Параметры FFTCalculate передаются корректно. Думаю что, то поведение которое ты видишь в Visual Studio является unexpected behavior. Твоя программа под линуском сразу упала с seg fault. Ниже пример кода с ошибкой. Ты не проверяешь значения rev[i], что оно может быть больше n (1024). calc_rev(n, log_N); for(int i = 0; i < n; ++i) if (i < rev[i]) swap(signal[i], signal[rev[i]]); Вот что у меня вывелось для первых десяти итераций из массива rev: 0 1024 1536 1280 1792 1152 1664 1408 1920 Надеюсь помог.

четверг, 9 апреля 2020 г.

Что означают следующие ANSI escape последовательности?

#c #linux #escape

                    
Просмотрел несколько источников, в том числе англоязычных, но нигде не нашел расшифровку
следующих escape-последовательностей:

\e[%i%d;%dr (В библиотеке S-lang присваивается переменной с именемScroll_R_Str)

\e[%i%d;%dH (Тут 3 аргумента, но для установки позиции, согласно документации, используется
2, я не понял этого момента..., в библиотеке S-lang данная последовательность присваивается
переменной с именемAbs_Curs_Pos_Str)

\e[P
\e[%dM
\e[%dL


Обновлено: неизвестны для меня также следующие последовательности (первые две, насколько
я понимаю, не являются ESC-последовательностями, так ли это?)

\016
\017
\e(B\e)0


Помогите пожалуйста в них разобраться и понять, что они делают?
    


Ответы

Ответ 1



Посмотрите man console_codes или то же самое в сети или по-русски. С ESC[ начинаются CSI-последовательности.

Ответ 2



Посмотрите тут: http://www.opennet.ru/docs/BSD/pascal/syscons/ansi.html Нашел там Esc[nM, Esc[nL - удалить / вставить n строк В английской википедии, вроде норм расписан принцип https://en.wikipedia.org/wiki/ANSI_escape_code int i, j; qDebug() << std::sscanf("12345", "%i%d", &i, &j) << i << j; выводит 1, 12345, 0 qDebug() << std::sscanf("12 345", "%i%d", &i, &j) << i << j; выводит 2, 12, 345. Может чем поможет

Компиляция 7-zip c помощью MSYS2

#cpp #c #gcc

                    
Подскажите, как компилировать 7-zip c помощью MSYS2
    


Ответы

Ответ 1



Подробная инструкция по компиляции с помощью MSVC доступна здесь. Добавлю вариант с компиляцией через Cygwin: Скачиваем Cygwin: выбираем версию x32. Устанаваливаем, например, в директорию C:\projects\tools\cygwin. Из доступных пакетов понадобятся: make, gcc/g++, wxwidgets. Соглашаемся с установкой предложенных пакетов. Скачиваем нужную версию 7zip под POSIX-системы: sourceforge. Распаковываем, например, в директорию C:\projects\other\7zip\source. Запускаем Cygwin.bat, переходим в директорию, где распакована библиотека 7zip: cd /cygdrive/c/projects/other/7zip/source. В директории с исходниками есть множество makefile для различных платформ, выбираем makefile.cygwin и копируем содержимое в файл makefile.machine. Выполняем make -j4 для компиляции цели all. Редактируем файл install.sh для указания своего пути установки скомпилированных файлов. Находим параметр DEST_HOME и изменяем его, например, так: /cygdrive/c/projects/other/7zip/build. Выполняем ./install.sh Теперь в каталоге /bin расположен исполняемый файл 7za.exe. Для его запуска копируем следующие библиотеки: cyggcc_s-1.dll, cygstdc++-6.dll, cygwin1.dll, из каталога cygwin_install_dir/bin. 7zip готов к использованию

Автодополнение для Си

#c #sublime_text #sublime_text_3

                    
Меня интересует автодополнение кода для Си в Sublime Text 3. Мне нужно, чтобы после
подключения заголовка какой-то плагин давал подсказки, подобно intellisense из Visual
Studio. Я "нагуглил" какие-то Clang autocomplete и тому подобное, но они нормально
не работают. 

Все мои плагины:



Из автодополнений у меня есть ключевые слова а-ля struct, typedef, типы переменных
etc. Но нет автодополнения (или, можно сказать, подсказок) по подключаемым файлам.
Например, тот же stdio.h — у меня автоподолнение только ОДНОЙ функции printf.
    


Ответы

Ответ 1



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

вторник, 7 апреля 2020 г.

Как определить размер функции в программе?

#cpp #c

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


Ответы

Ответ 1



Универсального решения не существует. Особенно если вы пишите на C++. А вообще, вот занимательное чтиво прямо на тему твоего вопроса: https://rsdn.ru/forum/cpp/2333802.hot Если коротко, то можно попытаться так: static int test_proc() { return 1; } static void size_proc() {} static size_t test_proc_size() { return (uintptr_t)((uintptr_t)(void*)size_proc - (uintptr_t)(void*)test_proc); } но вообще никаких гарантий, особенно в том, что size_proc так и останется сразу за test_proc. Ну и в развитие данной темы: можно попробовать получить адреса всех символов, отсортировать по возрастанию, размер между твоей функцией и следующим символом вполне может оказаться искомой величиной.

Ответ 2



Функция в С/С++ не обязана быть непрерывной последовательностью инструкций машинного кода с четко выраженным началом и концом. Если несколько функций содержат одинаковый завершающий блок кода ("эпилог"), оптимизирующий компилятор может включить его в бинарник только в одной функции, а в других заменить его на инструкцию перехода в первую. В таком случае понятие "размер функции" становится неоднозначным. Кроме того, попытка перенести машинный код из одного процесса в другой "как есть" скорее всего закончится неудачей, ведь инструкции часто оперируют относительными адресами. Более правильным решением было бы реализовать инжектируемый блок кода полностью в виде ассемблерной вставки, как например здесь. Тем не менее, API для получения размера функции (как справочной информации) существуют. Например, так это можно сделать в Windows с помощью dbghelp: #include #include #include #include "DbgHelp.h" #pragma comment(lib, "Dbghelp.lib") struct Function { const char* name; unsigned int size; bool success; }; BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID context) { Function* pfstruct = (Function*)context; if (strcmp(pSymInfo->Name, pfstruct->name) == 0) { pfstruct->size = SymbolSize; pfstruct->success = true; return FALSE; //закончить поиск } return TRUE; //продолжить поиск } // Находит размер функции fname и помещает в переменную resultvar // Требует наличия отладочных символов (PDB-файла) в каталоге с программой bool GetFunctionSize(const char* fname, unsigned int& resultvar) { bool ret; Function fstruct; fstruct.name = fname; fstruct.size = 0; fstruct.success = false; HANDLE hProcess = GetCurrentProcess(); //текущий процесс char Mask[] = "*!"; //искать среди всех модулей BOOL status; status = SymInitialize(hProcess, NULL, TRUE); //загрузка символов if (status == FALSE) { printf("SymInitialize failed. Error code: %d\n", GetLastError()); return false; } //поиск символов if (SymEnumSymbols(hProcess, 0, Mask, &EnumSymProc, (void*)&fstruct)) { if (fstruct.success != false) { resultvar = fstruct.size; //возвращаем размер ret = true; } else { printf("Symbol [%s] not found\n", fname); ret = false; } } else { printf("SymEnumSymbols failed. Error code: %d\n", GetLastError()); ret = false; } SymCleanup(hProcess); return ret; } //********************************** void Func() { printf("Hello, World!\n"); } int main(int argc, char **argv) { uintptr_t p = (uintptr_t)&Func; printf("Func address: 0x%x\n", (UINT)p); unsigned int size = 0; if (GetFunctionSize("Func", size) != false) { printf("Func size: %u bytes", size); } getchar(); return 0; } При использовании Visual Studio 2017+ для корректной работы данного кода необходимо собирать проект с параметром /DEBUG:FULL (см. /DEBUG).

Работа рекурсивной функции, суть на машинном уровне

#cpp #c

                    
void preOrderTravers(Node* root) {
if (root) {
    printf("%d ", root->data);
    preOrderTravers(root->left);
    preOrderTravers(root->right);
    }
}


Как работает рекурсия?
Вот допустим, что в обходе бинарного дерева мы вышли на левый нижний узел. Я так
понимаю, формируются стек вызова рекурсивной функции, и, дойдя до тупика, машина переходит
на предыдущий шаг и выполняет preOrderTravers(root->right). Так, да? Просто я где то
что то читал но не могу сейчас найти. 
    


Ответы

Ответ 1



Каждый вызов функции преобразуется в команду типа call xxx. В результате выполнения этой команды в стек заносится адрес возврата. Пока не достигнуто дно рекурсии функция не завершается, а вызывает сама себя. Когда достигается дно рекурсии функция завершается. При этом выполняется команда типа ret, которая выполняет переход по сохранённому в стеке адресу - происходит возврат на один уровень вверх. Таким образом, в случае дерева, функция вызывает себя до достижения листа, что является признаком дна рекурсии. После этого происходит возврат из вызванных функций.

суббота, 4 апреля 2020 г.

Как распечатать символ стрелки?

#linux #c

                    
Выяснил, что символы стрелок имеют следующие ASCII коды:

72 - вверх
75 - влево
77 - вправо
80 - вниз


Но эти же коды имеют некоторые буквы в верхнем регистре.

Возможно, эта информация ошибочна, но при проверке мне никак не удалось напечатать
символы стрелок.
Подскажите пожалуйста как это сделать через обычный printf?
Поддерживается только ASCII.
    


Ответы

Ответ 1



эти коды хоть и соответствуют стрелочкам, но не все так просто - они там составные. То есть, код стрелки - это два байта, а не один. И первый байт Вы забили указать. Этот байт - 224. То есть, код стрелки вверх - 224 72. Вот только распечатать их нельзя. Это управляющие символы клавиатуры. Более того, их нет в стандартной аски таблице. Когда то давно, когда был дос и нужны были стрелочки, делали кодогенераторы. То есть, готовиться своя таблица, в которой прописано отображение каждого символа. И можно взять часть символов, записать туда правильные картинки и использовать. Я даже не знаю, возможно ли это сейчас, но думаю, что все возможно. В любом случае, можно перевести видеорежим в графический и рисовать красиво.

Ответ 2



Используйте эти коды: ASCII value of character ↑: 24 ASCII value of character ↓: 25 ASCII value of character →: 26 ASCII value of character ←: 27

четверг, 2 апреля 2020 г.

SDL_CreateThread и барьер памяти

#cpp #c #многопоточность #sdl2

                    
До запуска дополнительного потока создается семафор, который используется в создаваемом
потоке:

// Main thread:
SDL_sem* sem = SDL_CreateSemaphore(0);
SDL_CreateThread(...);

...

// Second thread:
SDL_SemWait(sem);


Вопрос - могут ли поменяться местами (компилятором/процессором) создание семафора
и потока? (и возникнет ошибка при обращении к ещё не созданному семафору в новом потоке).
    


Ответы

Ответ 1



Ключевое свойство всех оптимизаций компиляторов придерживающихся стандартов в том, что они не меняют результат вычислений, если в исходном коде нет UB. Исходя из этого можно быть вполне уверенным, что компилятор не переставит местами вызовы функций, покуда не будет точно уверен, что у них нет побочных эффектов (например, для gcc если они не объявлены с __attribute__(pure)). Таким образом, если вызов SDL_CreateSemaphore(0) идёт до SDL_CreateThread(...), то можно не боятся, что при исполнении они как-то поменяются... Конечно всегда может представить сферический компилятор в вакууме, который делает всё что ему вздумается, но это уже совсем другая история... Также может быть столь же сферическая библиотека реализующая свои вызовы, как отложенные, но это уже проблема библиотеки, и пользователь об этом беспокоиться не должен... И ни к любой вменяемой реализации SDL, ни к любому вменяемому компилятору это всё не относится...

Преобразовать массив строк из статического в динамический

#c #строки

                    
нашел код

char string[]=  "abc/qwe/jkh";
char *array[10];
int i=0;

array[i] = strtok(string,"/");

while(array[i]!=NULL)
{
   array[++i] = strtok(NULL,"/");
}


И задался я целью сделать его более универсальным т.е. добавить динамическое выделение
памяти.

#include 
#include 

char *string = "Value1,123,Value2,456,Value3,789,"; // запятая в конце необходима
char **array_of_strings = NULL; // указатель на указатель строк
int i = 0;
long comma_counter = 0;
int eachLine = 0;

// считаем количество запятых, чтобы понять сколько нам нужно памяти

for (i = 0; i < strlen(string); i++) {
    if (string[i] == ',') {
        comma_counter++;
    }
}
printf("Commas counted: %d\n", (int)comma_counter);

array_of_strings = malloc(comma_counter * sizeof(char*)); // выделяем столько сколько
насчитали 

if (array_of_strings == NULL) {
    printf("Memory allocation failed!");
    exit(1);
}


И вот первая проблема. strok возвращает указатель, и мне его нужно записать в array_of_strings
позиция 0.

Как записать строку в array_of_strings[0]?

---> = strtok(string, ",");
--->printf("%s\n", array_of_strings[eachLine]);

--->while(*array_of_strings) // дальше надо делать снова вызов выделения памяти
--->{
--->    array_of_strings = malloc();
--->    array_of_strings[++i] = strtok(NULL, ",");
--->    array_of_strings++;
--->}


// ну а это будущий вывод строк на экран
for (i = 0; i < comma_counter; i++) {
    printf("%s\n", array_of_strings[i]);
}

    


Ответы

Ответ 1



Пример разбивки строк есть здесь. Часто пользуюсь этим ресурсом. Что-то такое может быть: char string[] = "Value1,123,Value2,456,Value3,789,"; int comma_counter=6; char *pCh; char **array_of_strings=(char**)malloc(sizeof(pCh)*comma_counter); //переменная string изменится int k=0; char * pch= strtok(string, ","); while(pch!=NULL) { array_of_strings[k] = (char*)malloc(strlen(pch)*sizeof(char)+1); if (array_of_strings[k]==NULL) exit (1); strcpy(array_of_strings[k], pch); pch = strtok (NULL, ","); k++; if(k==comma_counter) pch=NULL; } printf ("%s \n %s", array_of_strings[0],array_of_strings[comma_counter-1]); //не забывайте освобождать память for(int i=0;i

Какой алгоритм перевода сишного кода в ассемблер, который понимает процессор?

#c #ассемблер

                    
Вник в написание программ для микроконтроллеров (мк). Суть такая, что у каждой модели
мк есть определенный набор команд с разными опкодами. Например возьмем ОС виндовс.
Есть различное количество компьютеров с разными процессорами. Но программы написанные
на Си на винде работают на всех этих компах. Т.е. эти проги компилируются в какой-то
виндовый asm, а после драйвера на процессор переводят эти команды в те, которые понимает
процессор, или как это происходит? Есть ведь процессоры с какими-то специализированными
командами и если на этих процах все заработает, то на остальных нет? Хочется узнать
алгоритм перевода сишного кода в циферки, которые понимает процессор.
    


Ответы

Ответ 1



Хочется узнать алгоритм перевода сишного кода в циферки, которые понимает процессор. Для большинства современных систем это двухэтапный процесс: Текст на языке программирования (например - С) переводится коды конкретного процессора. Например - х86, ARM, PowerPC... Получается "объектный модуль". К полученному объектному модулю "пришиваются" все необходимые модули из сторонних библиотек. Получается "исполнимый модуль". Разумеется, этот модуль может быть выполнен только на данном конкретном процессоре, в рамках конкретной операционной системы. Программа, скомпилировнная для х86 не может быть выполнена на ARM или PowerPC. Программа, скомпилированная для седьмой версии виндовоза, скорее всего, не может быть выполнена на устаревших версиях этой ОС. Тем более, она не может быть выполнена под Linux или Android. Здесь не говорим о т.н. "скриптовых" языках программирования, а только именно об исполняемых модулях. Никакого "драйвера" первводящего ассемблер в команды процессора не существует. Любой ассемблер "заточен" под конкретный процессор и конкретную ОС.

Ответ 2



У процессоров х86 базовый набор команд стандартизирован. Конечно есть расширения https://ru.wikipedia.org/wiki/Расширения_архитектуры_x86. Разработчики программного обеспечения, прежде чем использовать их в собственных программах, должны выполнить специальную команду CPUID, которая сообщает о наличии тех или иных расширений. Разработчики используют эти дополнительные возможности при низкоуровневой оптимизации. В основном компиляторы не пользуются расширенными инструкциями или же могут оптимизировать самый тривиальный код. Для нормальной оптимизации и качественного использования этих расширений опять таки нужен разработчик. === А насчет того что в разных ОС программы не могут работать. Так программа еще может обращаться к различным функциям ОС API и пр. Ну а в разных ОС эти функции могут различаться.

вторник, 31 марта 2020 г.

Как узнать, был ли тип уже объявлен ранее?

#c #typedef


Допустим, есть такой код:

typedef int i32;


Как узнать, был ли тип i32 уже объявлен ранее? Т. е. что-то типа #ifdef только для
typedef.
    


Ответы

Ответ 1



Никак не узнать. Если дальновидный автор кода предвидит необходимость такой проверки в будущем, он обычно сопровождает определения типов определением дополнительного макро. Так, например, стандартный заголовочный файл содержит определение макро __bool_true_false_are_defined со значением 1.

Ответ 2



Есть метод двойной компиляции, знаю как в Linux через Makefile это делать. Сначала компилируется простой файл с typedef. Затем проверяется код ошибки компиляции, и задаётся #define TYPEREDEFINIED. Makefile : main.o : main.c main.h ..TAB..: if gcc checktypedef.c &> /dev/null ; then ; else OPTIONFORGCC = -DTYPEREDEFINIED ; fi ..TAB..: gcc OPTIONFORGCC main.c .. checktypedef.c : # include <все заголовки из main> typedef unsigned char BYTE ; main.c : # include <все заголовки> # ifdef TYPEREDEFINIED # error Опять! # endif

Ответ 3



Возможно обьявить все используемые хеадеры в одном файле test.c например, потом: gcc -E test.c | grep "int32my" и смотрим результат :)