Как пропатчить Remote Debugger 2012 под Windows XP

Вторая на данный момент по популярности винда более не поддерживается официально. Под нее не будут выпускаться патчи, ну почти. Но что действительно заставляет меня переходить с нее на что-то более новое, так это невозможность работы на ней Visual Studio старше 2010-й версии. Конечно, я не нахожу в этом серьезной проблемы, но по ряду причин XP у меня прочно засела на виртуалке, и я продолжаю ее использовать в таком виде. VC++ 2012/2013, кстати, хотя не работает на XP, но позволяет собирать под нее программы. В противном случае было бы очень сложно заставить разработчиков переходить на новые студии, потому что еще очень много стороннего софта заявляет поддержку старых винд. Но чтобы все-таки усложнить людям жизнь, под XP кроме самой студии не работает также Remote Debugger. То есть писать что-то под эту ненавистную MS операционку пока можно, но вот отлаживать уже никак (по крайней мере, в удобной среде VS). Это доставило мне некоторые неудобства, и я решил исправить ситуацию. Просто взял этот ремоут дебаггер и пропатчил, чтобы работал. Собственно, вот он. Правда, он умеет только native код, т.к. мне этого более чем достаточно. Если вам тоже, можно брать и юзать. Ну а для тех, кому просто интересно, суть проделанных извращений под катом.

Collapse )

Сокращение правого операнда побитового сдвига

Операторы побитового сдвига берут левый операнд и сдвигают его двоичное представление на количество бит (вправо >> или влево <<), указанных в правом операнде. В простейших случаях такие операции эквивалентны делению или умножению на степень двойки. Некоторые особенности появляются, если берутся числа отрицательные или знаковые. Например, в C++ (Глава Стандарта 5.8) сдвиг влево отрицательного значения ведет к undefined behavior, а сдвиг право определяется реализацией. Однако сдвиг положительного (или беззнакового) значения вправо E1 >> E2 всегда должен быть эквивалентен целой части E1 / 2E2.

Кстати, есть язык, в котором нет беззнаковых типов. В нем сдвиг вправо старшие биты заполняет не нулем, а значением знакового бита (для отрицательных чисел единицей). Поскольку это не всегда ожидаемое поведение, в языке есть специальный оператор беззнакового сдвига вправо >>>. Старшие биты он заполняет нулем.

Но это еще не все. В спецификациях языков C# (п. 14.8) и Java (п. 15.19) есть такое понятие, как сокращение правого операнда. В действительности сдвиг осуществляется не на то число бит, которое записано в правом операнде, а на его значение по модулю разрядности левого операнда. То есть происходит примерно следующее:
E1 >> (E2 % (sizeof(E1) * 8)) или, точнее,
E1 >> (E2 & (sizeof(E1) * 8 – 1))
Это приводит к неожиданным спецэффектам, например, сдвиг на 1000000 вообще не будет делать никаких сдвигов. Трогательную историю, зачем так было сделано, можно почитать здесь.

А вот совершенно внезапным для меня оказалось, что некоторые популярные компиляторы C++ тоже делают сокращение, хотя никакого намека на это я не нашел ни в Стандарте, ни в аннотированном руководстве. Я проверил в Visual C++ 2005, MinGW 4.5.2 и CodeGear C++ 2009 – во всех присутствует сокращение для всех целочисленных типов (кроме, разве что, long long, для которого оно есть лишь в MinGW).

Если кто-то знает причину этого странного явления, расскажите, а?

UPD: Visual C++ 2008/2010 и Intel C++ Compiler 11 выдают аналогичный результат.
Посмотрел, во что оно компилируется (VC++), получается что-то вроде:
mov esi, dword ptr [E1]
mov eсx, dword ptr [E2]
sar esi, cl
Здесь следует обратить внимание на семантику мнемоники sar. В качестве второго операнда может быть только конкретное значение, либо регистр cl (младший байт регистра ecx). В последнем случае происходит сокращение cl по маске 0x1F, то есть по модулю 32.

На код вида 121 >> 1000000; VC++ выдает предупреждение "shift count negative or too big, undefined behavior". Причины, почему too big приводят к ub, находятся за горизонтом моего непонимания, однако уже объясняют, почему все компиляторы ведут себя undefined.
  • Current Music
    Draconian — [Arcane Rain Fell #08] Death, Come Near Me

Ковариантные возвращаемые типы

Есть в C++ такая фича. Допустим, есть класс с виртуальным методом, возвращающим указатель на себя. Наследуясь от него, можно переопределить этот метод, причем в качестве возвращаемого типа допустимо использование указателя на производный класс. Этот механизм называется ковариантными возвращаемыми типами. Каноническим примером послужит метод clone, создающий копию объекта в куче и возвращающий указатель на него. Примерно так это может выглядеть:
 

Collapse )

  • Current Music
    ERA - [Era Classics #06] Malher + Adagieto + 5th Symphony

Задача по C++

Есть код.
 
class Scope
{
    struct Base
    {
        ~Base()
        {
            std::cout << "~Base" << std::endl;
        }
    protected:
        Base() { }

    };

    friend struct Local;
};

struct Local
{
    class Derived : public Scope::Base
    {
        Derived() { }
        ~Derived() { }
    };
};

Нужно написать нечто, вызывающее деструктор класса Base.
  • Current Music
    Vangelis — [Oceanic #05] Islands of the Orient

Калькулятор Windows

Вы когда-нибудь замечали, что в стандартном калькуляторе windows такой большой циферблат (инженерный вид), а ввести можно так мало? В тоже время нетрудно заметить, что разрядность чисел, с которыми он может работать, превышает 64 бита, а это означает, что длинную арифметику калькулятор реализует. Так почему бы ей не воспользоваться в полной мере? Калькулятор поддерживает от 0 до 64 разрядов (десятичных, в том числе), по умолчанию которых 32. Изменить можно командой: calc -p:#. Например, calc -p:64 позволит уже отобразить 49! полностью.
  • Current Music
    Luca Turilli — [The Infinite Wonders of Creation #04] Altitudes

Сочетания и битхак

Задумал написать перебор сочетаний, представляя результат в виде битовой маски. Хотелось сделать совсем без циклов, но один все-таки понадобился. Итак, будем сочетания перебирать в лексикографическом порядке. Только для удобства первая выборка будет представляться в виде 111...111000...000, что соответсвует подмножеству { 1, 2, 3, ..., k }, следующая 111...110100...000 => { 1, 2, ..., k-1, k+1 }, последняя 000...000111...111, соответственно, { n-k+1, n-k+2, ..., n }. Для получения следующего сочетания рассмотрим два случая:
  • Самый младший бит 0. Тогда ясно, что последний элемент в текущей выборке можно увеличить на 1, то есть самый младший установленный бит нужно сместить на одну позицию вправо. Сделать это можно так: n = n ^ (n & -n) | (n & -n) >> 1. Из жж товарища sharpc можно узнать, что кодом n & -n получается число с самым младшим установленным битом. Xor с исходным его снимает, а следующий Or устанавливает его на одну позицию правее.
  • Младший бит 1. В этом случае возможна ситуация, что справа какое-то число r единичных битов (если r == k, то это последнее возможное сочетание). Слева до r имеется число, которое полностью соответсвует первому случаю, то есть имеет вид 11..1100... С ним делается тоже самое, а вот r млаших битов нужно сместить на максимально возможное количество положений влево, пока они не перекрывают хоть один бит в нашем числе. Вот эта часть для меня стала самой трудной и для которой я так и не придумал закрытой формулы :) Решение у меня вышло такое. Сначала получаем число, состоящее только из самых младших r единичных битов, формула имеет вид p = ((n + 1) & -(n + 1)) - 1 и основана на уже упоминавшемся фокусе. Далее ясно, что если его вычесть из исходного числа, то задача сводится к первому пункту. И наконец нам нужно число p сдвинуть влево настолько, насколько это возможно без пересечения, а потом сложить с ответом.
bool next_comb(int& mask, int k) {
if(mask == (1 << k) - 1) return false;
if(!(mask & 1))
mask = mask ^ (mask & -mask) | (mask & -mask) >> 1;
else {
unsigned int u = mask + 1;
unsigned int n = (u & -u) - 1;
u -= n + 1;
u = u ^ (u & -u) | (u & -u) >> 1;
while(!(u & n << 1)) n <<= 1;
mask = u | n;
}
return true;
}

Принимаются предложения по оптимизации :)
  • Current Music
    Annasophia Robb - [Bridge To Terabithia #01] Keep Your Mind Wide Open

wqNotes

Есть такая программа. Это суть есть редактор с древовидной структурой. В далеком 2007 году, летом, мы с sharpc пришли к выводу, что пора бы перестать складировать на винчестере кучу текстовых файлов с заметками и написать собственную, удобную и красивую утилитку для решения этой проблемы. И хотя мы люди деловые :), кое-что готово уже сейчас. wqNotes хостится на коде гугла, репозиторий там же. C#. Если кто заинтересуется, доступна бета версия 0.9.3. Комментарии, пожеланиия, угрозы и т.п. приветствуются.
  • Current Music
    Tristania - [Illumination #10] The Ravens

Совет труъ-программистам

Если вы считаете себя профессиональным программистом, пишете сложнейшие высокопроизводительные программные системы, которые распространяются на DVD, то в этом вам может помочь следующий код (секрет профессионалов!):
#define TrueCoder(Mb) class A{char a[Mb*1048576];public:A(){memset(a,-1,1);}};A a;

P.S. Компилировать в Release, VC++ 2005/2008.
  • Current Music
    Nightwish - [Century Child #08] Feel For You

Короткий формат размера

Многие наверно знакомы с курьезом, связанным с трактованием широкораспространенных приставок системы СИ, примененных к единицам информации. Сколько байт в мегабайте? А сколько килобайт? Не смотря на несоответствие десятичных и двоичных величин (103 и 210, 106 и 220, etc), все твердо помнят, что в килограмме 1024 грамма, а в килобайте 1000 байт. Между тем, производители жестких дисков (а также CD/DVD болванок и дискет) неплохо на этом выигрывают.
Collapse )
  • Current Music
    Sirenia - [Sirenian Shores #02] Save Me From Myself (Remix)

Структуры данных .NET

Недавно в программе, реализуемой на C#, понадобился тип данных множество. Беглый поиск при помощи IntelliSense в пространстве имен System.Collections.Generic не дал положительных результатов. Священный источник знаний жрецов до-диеза оказался малоинформативным в данном вопросе. Впрочем, вскоре я обнаружил, что в .NET 2.0 такой простой и полезной структуры данных нет, а появится лишь в .NET 3.5. Казалось бы, мелочь, но странно то, что структуры данных носят намного более фундаментальный характер и имеют большую значимость (и необходимость), чем какая-нибудь сериализация или механизм reflection. Так или иначе, быдлокодеры разработчики дотнета не реализовали ни множество, ни удобный STL'ный класс pair, ни многого другого (разнообразных деревьев), касаемого структур данных.

Не забывайте, как с помощью веревки достаточной длины стрелять себе в ногу :)
  • Current Music
    Theatre of Tragedy - [Aegis #01] Cassandra