• Как скрыть адрес вызываемой функции в C++?

    @rPman
    В коде, указанном в вопросе написана белиберда
    В конструкторе предлагаешь сделать присваивание
    vProtect = Protect;
    глобальной переменной vProtect имя класса Protect (потому что у тебя Protect и класс и переменная типа cProtect, (то что компилятор тебе это позволил уже бардак), если переименовать cProtect мембер Protect в protect (как рекомендует большинство code styling - имена классов с большой буквы, имена переменных - с маленькой, чтобы не запутаться), а еще тип vProtect у тебя - указатель, а Protect - нет, если будут оба указатели то само собой все будет собираться, но все равно смысла это иметь не будет.
    -----------------------

    Теперь про твой вопрос в заголовке, почти ничего не имеющий общего с текстом вопроса:
    Как скрыть адрес вызываемой функции в C++?
    в контексте обфускации, подразумевается что по декомпилированному исходному коду должно быть не ясно, какой именно метод будет вызываться (т.е. для анализа требуется отладка, что сложнее/дороже), значит хранить адреса методов нужно в каких то переменных, например массивах, а выбор следующего вызываемого метода делать на основе каких то вычислений по коду.

    В c++ для этого реализован класс std::function, пример использования для вызова именно метода класса (для простоты пример без аргументов но с аргументами все то же самое, надеюсь ты понимаешь, что у тебя должны быть одинаковые аргументы и типы во всех методах, или должны быть группы для разных типов, но чем больше групп тем проще анализ кода, иначе тупо по типам и количеству аргументов все можно будет понять)
    // определяем класс
    class MyClass
    {
      public:
      void myFunA(){std::cout<<"A";};
      void myFunB(){std::cout<<"B";};
    };

    однократно где то инициализируешь массив адресов функций (никто не мешает по коду это перемешивать)
    std::function<void(MyClass*)> functions[]={&MyClass::myFunA,&MyClass::myFunB};

    вызов метода по номеру x
    MyClass obj;
    functions[x](&obj);
    Ответ написан
    3 комментария
  • Какую роль играют float и double в скобках?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Такая запись имени типа в скобках в выражении - это явное приведение типа. Тут вы указываете компилятору, что выражение надо преобразовать вот к такому вот типу (флоат, в данном случае).

    float нужен вам в начале, потому что вещественные константы имеют тип double. Поэтому у eps/2.0 и 1.0 в первом цикле имеют тип double, все вычесляется в double. Преобразовав одно из выражений в float вы получаете то, что вам надо. Без этого все вычисления идут в double и ответ находится не тот. На самом деле там float при сравнении все-равно расширяется до double но на результат сравнения это не влияет в данном случае.

    Еще, вместо явного приведения типов, можно поставить f после вещественных констант, чтобы указать компилятору, что это float:
    while (1 + eps/2.0f != 1.0f){

    Тогда вычисления будут во float и ответ будет правильный.

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

    Adamos
    @Adamos
    Первый float - это приведение выражения за ним к типу float.
    Вообще говоря, ненужное, поскольку сложение int и float и без этого приведения будет float.

    Второй double - демонстрация того, что писавший вообще не понимает, что делает.
    Ибо тут к вещественному типу приводится... булев результат сравнения.
    Ответ написан
    8 комментариев
  • Каковы правила конвертации указателя на массив неопределенной длины в указатель на массив определенной длины?

    Adamos
    @Adamos
    С++ - язык более высокого уровня, тут компилятор не позволит вам выстрелить себе в ногу неявным приведением сена к соломе. Нужно объявить его явно.
    static_cast - если компилятор готов согласиться с вами, что одно можно просто привести к другому во время компиляции.
    dynamic_cast - если вы приводите указатель на родительский класс к указателю на дочерний
    и reinterpret_cast - если вы приводите по-сишному, "ногой в дверь", уверены в себе и не нуждаетесь в подсказках компилятора насчет того, что делаете.
    Ответ написан
    4 комментария
  • Почему T * может работать ощутимо быстрее (~ на 25-30%) в качестве хранилища данных, чем std::byte *?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Надо смотреть, что там компилятор нагенерировал.

    Создайте 2 функции, которые отличаются только вот в этих вот местах.
    Вставьте код в https://godbolt.org/

    Смотрите ассемблерный код для двух функций.

    Может, срабатывает strict aliasing. Видя тип T сомпилятор понимает, что эта переменная не может быть изменена какими-то другими std::byte в соседнем коде и может, например, пропустить загрузку-выгрузку данных в регистр из памяти.

    Может вообще что-то другое.

    Единственный вариант разобраться - это смотреть на ассемблерный код функций, которые вы и сравниваете. Не каких-то кусков, оттуда надерганных, а функций целиком.
    Ответ написан
    Комментировать
  • Почему можно не указывать virtual в файле реализации?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему можно не указывать virtual в файле реализации?

    Не то чтобы "можно не указывать". Нужно не указывать. Потому что так говорит стандарт.
    И потому что виртуальность функции -- это не свойство функции, а свойство класса которому она принадлежит. Код функции не зависит от того, виртуальная она или нет.
    Ответ написан
    4 комментария
  • Как сократить код с подпрограмой?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Эти три функции идентичны, с точностью до переименования локальных переменных. Вы три раза написали одно и тоже. Можно 2 функции просто удалить и использовать отсавшуюся три раза.

    Ну какая разница, как у вас там переменная называется sA или sB - результат будет один и тот же.

    Да, может вы путаетесь, но аргумент в функции можно тоже переменовать. Хоть там и написано int masivA(int* a), этот a - это аргумент. Он никак не привязан к массиву a в main(). Туда можно передать и a и b и любой другой массив.
    Ответ написан
    4 комментария
  • Почему Config::search у меня возвращает мусор?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Проблема вот в этой строчке:
    return str.c_str();

    Тут вы возвращаете указатель на внутренние данные у str. Но при выходе из функуции str уничтожается - это же локальная переменная. В итоге у вас получается висячий указатель (указатель на память, которой вы уже не владеете). Эту память какая-то другая часть вашей программы переиспользует и там остается что-то не ваше, выглядещее для вас, как мусор.

    Вообще, это undefined behavior - доступ к висячему указателю. Программа вполне может и аварийно завершится.

    Для решения этой проблемы возвращайте std::string. Или выделяйте char* вручную, через new[] (только не забудьте указатель потом удалить в вызывающем коде). Но лучше, конечно, возвращать string и не мучатся с ручным управлением указателями.
    Ответ написан
  • Почему не возникает ошибка при вводе слова больше длины чем выделена память?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    должна возникнуть ошибка, но по факту её не возникает.

    А ты собери свою программу с санитайзером памяти (-fsanitize=address) и будет тебе ошибка.
    Обращение к памяти за пределами выделенных массивов -- это UB, отсутствие видимого эффекта -- допустимый вариант поведения при UB.
    Ответ написан
    Комментировать
  • Почему при выводе массива в консоль пишется что-то странное?

    Nipheris
    @Nipheris Куратор тега C++
    Array-to-pointer decay.
    There is an implicit conversion from lvalues and rvalues of array type to rvalues of pointer type: it constructs a pointer to the first element of an array. This conversion is used whenever arrays appear in context where arrays are not expected, but pointers are:
    ...

    Ваш массив неявно сконвертился к указателю на int, т.к. оператор << класса std::ostream массивы выводить не умеет, а вот указатели - вполне себе.
    Ответ написан
    Комментировать
  • Почему при выводе массива в консоль пишется что-то странное?

    GavriKos
    @GavriKos
    Правильный вывод УКАЗАТЕЛЯ на начало памяти где массив содержится. А массив вы так просто не выведете
    Ответ написан
    Комментировать
  • Тип с точностью до 4 знаков C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Есть. Называется int. Вам надо хранить количество десятитысячных в числе. Иными словами, вы вместо x храните в int x*10000. При выводе делите на 10000 (и установите выводить 4 знака).

    Такие числа можно просто складывать и вычитать. При умножении надо будет результат поделить нацело на 10000 (или округлить к ближайшему, делящемуся на 10000 и потом отбросить 4 нуля). При делении - наоборот. Надо сначала домножить числитель на 10000, а потом поделить нацело на знаменатель (возможно стоит подумать об округлении к ближайшему целому).

    Upd: И вообще, раз уж разговор о C++, то можно реализовать свой класс. Там можно даже отдельно хранить целую часть и 4 знака после запятой. Если вам встроенной точности int/int64_t не хватает. Все математические операции можно переопределить и работать, как со встроенным типом. Вообще, по-умному, это называется fixed point numbers.
    Ответ написан
    Комментировать
  • Как решить проблему в коде не запускается код, основные операции над бинарным деревом?

    mayton2019
    @mayton2019
    Bigdata Engineer
    Это не бинарное дерево. Ерунда какая-то. Обычно когда объявляют такое дерево -то считают что это
    бинарное дерево поиска. И в нем должны быть функции для расстановки узлов относительно значения Data.

    Здесь что? Непонятно. Рандомным образом раскидали? Зачем?
    Ответ написан
    Комментировать
  • Как работать с указателями?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы там поменяли местами значкения двух переменных указателей. Поскольку переменные (указатели) переданы по значению, то вне функции ничего не поменялось.

    Вы же менянте местами значения int, значит временная переменная tmp должна быть int, а указатели надо разименовывать.
    Ответ написан
    Комментировать
  • Почему выводится другое значение вместо ожидаемого?

    HighTechLowLife
    @HighTechLowLife
    https://en.cppreference.com/w/cpp/language/eval_order

    2) If a side effect on a memory location is unsequenced relative to a value computation using the value of any object in the same memory location, the behavior is undefined.

    cout << i << i++; // undefined behavior until C++17
    a[i] = i++;       // undefined behavior until C++17
    n = ++i + i;      // undefined behavior
    Ответ написан
    Комментировать
  • Почему появляется такая ошибка?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    что тут неправильно?

    для однозначного ответа на этот вопрос не хватает определения типа Student.
    Но судя по тому как всё падает, в Student есть не-POD поля, выделяющие и освобождающие память, например std::string или что-то типа того. Загружать их из файла просто читая записанное ранее содержимое памяти нельзя, потому что загруженные указатели будут ссылаться на невыделенную память, такие типы данных нужно по-честному сериализовывать.
    Ответ написан
    Комментировать
  • Что возвращает return в С++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Зависит от кода функции и опций компилятора.

    Советую всем программистам на C++ хотябы почитать про ассемблер.
    Стек, регистры, вот это вот все. Тогда станет понятно, как работает процессор.

    Тогда станет понятно что "сам объект tmp" никак не вернуть. Это локальная переменная, лежащая на стеке в части, которая будет отброшена при выходе из функции. Отсюда вытекает, что вообще говоря, там должна быть копия.

    Но есть такая оптимизация, как RVO. В стандарте даже прописано, когда конкретно она гарантирована. Тогда копии не происходит. При этом компилятор вообще не создает локальной переменной. А вместо этого сразу же работает с тем местом, куда надо будет возвращать значение.

    Если код и включенные оптимизации позволяют это сделать - то копии не будет. Но в общем случае - будет копия.
    Ответ написан
    Комментировать
  • Как создать диапазон чисел в массиве от -0.1 к 0.2,используя float и после ShellSort?

    sheerluck
    @sheerluck
    #include <random>
    #include <iostream>
    
    int main()
    {
        auto n = 9;
        auto rnd = std::random_device{};
        auto gen = std::mt19937_64{rnd()};
        auto dis = std::uniform_real_distribution<double>{-0.1, 0.2};
        auto res = std::vector<double>{};
        std::generate_n(
            std::inserter(res, std::end(res)),
            n,
            [&](){ return dis(gen); }); 
    
        for (const auto& elem: res)
        {
            std::cout << elem << '\n';
        }
    }
    Ответ написан
    Комментировать
  • Почему к итератору не прибавляется единица?

    Adamos
    @Adamos
    Итератор std::list - не итератор произвольного доступа, у него нет возможности перескочить несколько элементов, реализован только переход к предыдущему и следующему. Поэтому инкремент для него существует, а сложение - нет, и библиотека начинает искать по сусекам, к чему бы, реализующему сложение, его привести.
    К счастью, не находит ничего подходящего ;)
    Ответ написан
    Комментировать
  • Почему программа загружается в разных областях памяти?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему программа каждый раз занимает различные области памяти?

    Потому что современные ОС делают это намеренно, чтобы затруднить эксплуатацию уязвимостей в ПО. Это называется ASLR: address space layout randomization. Обычно есть способ отключить ASLR глобально либо для отлаживаемых программ, чтобы добиться воспроизводимости результатов.
    Так, например, в linux это делается глобально с помощью файла /proc/sys/kernel/randomize_va_space либо командой setarch -R для одного конкретного процесса. Отладчик gdb по умолчанию отключает ASLR для отлаживаемых программ.
    Ответ написан
    3 комментария