-
Notifications
You must be signed in to change notification settings - Fork 67
Instant notes (ru)
Распределение компилятором VC стека под переменные, определенные во вложенных областях определения внутри функции
void foo()
{
int a = 0;
{
char b[128];
}
{
char b[128];
}
}
Необходимый размер (sizeof(a) + sizeof(b) + sizeof(b)) = 260 будет выделен в начале функции. То есть, физически, данные первой переменной b могут наблюдаться в зоне видимости второй переменной b. Само-собой, если переменные имеют ctr/dtr то все это работает правильно для каждой из scope'ов. Меня интересовал только момент времени распределения пространства на стеке.
Мне было важно это выяснить для принятия решения о том, использовать ли один общий локальный буфер или разные для каждой зоны видимости.
Функции для работы с read-write блокировками Windows доступные во всех (или почти во всех) версиях Window
ntdll.dll
void WINAPI RtlInitializeResource(LPRTL_RWLOCK rwl);
void WINAPI RtlDeleteResource(LPRTL_RWLOCK rwl);
BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK rwl, BYTE fWait);
BYTE WINAPI RtlAcquireResourceShared(LPRTL_RWLOCK rwl, BYTE fWait);
void WINAPI RtlReleaseResource(LPRTL_RWLOCK rwl);
typedef struct _RTL_RWLOCK {
RTL_CRITICAL_SECTION rtlCS;
HANDLE hSharedReleaseSemaphore;
UINT uSharedWaiters;
HANDLE hExclusiveReleaseSemaphore;
UINT uExclusiveWaiters;
INT iNumberActive;
HANDLE hOwningThreadId;
DWORD dwTimeoutBoost;
PVOID pDebugInfo;
} RTL_RWLOCK, *LPRTL_RWLOCK;
size_t strlen(const char *)
одна из самых популярных функций стандартной библиотеки c/c++. Возвращает длину строки, переданной ей в виде константного указателя. То есть ищет завершающий ноль из вычисляет разницу между указателем на терминальный ноль и указателем на начало строки. Компиляторы обычно прекрасно оптимизируют эту функцию потому альтернативные реализации, если и могут как-то ее разогнать, то очень незначительно и часто с побочным эффектом.
Спецификация strlen имеет пару неприятных особенностей, следующих из того, что функция предполагает, что ей передается ненулевой валидный указатель и строка обязательно где-то заканчивается терминальным нулем. Если вы попытаетесь вызвать strlen(NULL), то ваша программа завершится по исключению доступа к памяти. По этому, часто в кодах можно встретить конструкцию вида:
size_t len = 0;
if(p)
len = strlen(p);
Так же, если передать функции указатель на участок памяти, внутри которого нет терминального нуля, то существует не мизерная вероятность получить исключение доступа к защищенному участку памяти. Кстати, альтернативные имплементации strlen, пытающиеся ускорить работу этой функции посредством использования SSE и AVX инструкций процессоров страдают от проблемы той же природы: "заглядывают" за терминальный ноль и, если доступная для чтения память заканчивается где-то сразу за этим адресом, то это вызывает исключение.
В случае использования strlen в коде на c++ следует иметь в виду, что не существует стандартной перегрузки этой функции для аргумента типа (const unsigned char *), соответсвенно, такой указатель придется явно преобразовывать к (const char *).
В качестве функции общего назначения, замещающей strlen(const char *) я использую простую замену sstrlen(const char *), которая проверяет аргумент на ноль и, если это так, то возвращает 0. Она совсем немного медленнее штатной strlen(), но безопасна. Кроме того, несколько перегруженных вариантов для аргументов типа (const unsigned char *), (const wchar_t *) и (const char16_t *) упрощают жизнь при работе с unicode-строками. Кроме того, если требуется, чтобы функция явно возвращала знаковый целый результат (int), то применяю тривиальные функции sstrleni() с таким же набором параметров, что и sstrlen().