Есть ли способ получить препроцессор C / C++ или шаблон или что-то подобное для изменения / хеширования __FILE__ и __LINE__ и, возможно, некоторых других внешних входных данных, таких как номер сборки, в один короткий номер, который можно указывать в журналах или сообщениях об ошибках?
(Намерение состояло в том, чтобы иметь возможность отменить его (в список кандидатов, если он с потерями), когда это необходимо, когда клиент цитирует его в отчете об ошибке.)
Скорее всего, это сделано для того, чтобы скрыть информацию от клиентов о том, где находится проблема, но число должно позволить ей быть полезной для сотрудников службы технической поддержки. У меня есть сомнения относительно размера базы данных, необходимой для обработки огромного количества возможных чисел.





Что ж, если вы сами показываете сообщение пользователю (вместо того, чтобы система отображала адрес сбоя или функцию), нет ничего, что могло бы помешать вам отобразить именно то, что вы хотите.
Например:
typedef union ErrorCode {
struct {
unsigned int file: 15;
unsigned int line: 12; /* Better than 5 bits, still not great
Thanks commenters!! */
unsigned int build: 5;
} bits;
unsigned int code;
} ErrorCode;
unsigned int buildErrorCodes(const char *file, int line, int build)
{
ErrorCode code;
code.bits.line=line & ((1<<12) - 1);
code.bits.build=build & ((1<< 5) - 1);
code.bits.file=some_hash_function(file) & ((1<<15) - 1);
return code.code;
}
Вы бы использовали это как
buildErrorCodes(__FILE__, __LINE__, BUILD_CODE)
и выведите его в шестнадцатеричном формате. Расшифровать было бы несложно ...
(Отредактировано - комментаторы правы, я, должно быть, был сумасшедшим, чтобы указать 5 бит для номера строки. Однако по модулю 4096 строки с сообщениями об ошибках вряд ли будут конфликтовать. 5 бит для сборки все еще в порядке - по модулю 32 означает что только 32 сборки могут быть невыполненными, И ошибка по-прежнему возникает в той же строке.)
У вас должны быть очень короткие исходные файлы для ЛИНИЯ, чтобы поместиться в 5 бит.
Он предлагает C / C++, но его собственные проекты могут быть написаны на Python (следовательно, требуется очень мало кода :) Шучу, конечно, комментарий Майка Б. уместен. Майк Джи, тебе следует пересмотреть свой ответ.
Вы оба абсолютно правы. Отредактировано, чтобы сделать строку 12 бит, а не 5, и явно модулировать строку #.
Вам нужно будет использовать функцию для выполнения хеширования и создания кода из __LINE__ и __FILE__, поскольку препроцессор C не может выполнять такие сложные задачи.
В любом случае, вы можете вдохновиться этим статья, чтобы увидеть, может ли другое решение лучше соответствовать вашей ситуации.
Что ж ... вы можете использовать что-то вроде:
((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )
Это не будет совершенно уникальным, но может сработать для того, что вы хотите. Можно изменить эти OR на +, что может лучше работать для некоторых вещей.
Естественно, если вы действительно можете создать хэш-код, вы, вероятно, захотите это сделать.
Здесь есть пара проблем. В основном вы используете && (логическое и), когда вы имеете в виду & (побитовое И), и все файлы, строковые константы которых находятся в пределах 64 КБ (что может быть большим числом в зависимости от компилятора), будут иметь одинаковые верхние биты. Средние биты более интересны.
Мне потребовались серийные значения в моем проекте, и я получил их, создав шаблон, который специализировался на __LINE__ и __FILE__ и привел к int, а также генерировал (как вывод времени компиляции в stdout) специализацию шаблона для его входов, что привело к строке номер этого шаблона. Они были собраны в первый раз через компилятор, а затем выгружены в файл кода, и программа была снова скомпилирована. В этот раз каждое место, где использовался шаблон, получило другой номер.
(сделано в D, поэтому это может быть невозможно в C++)
template Serial(char[] file, int line)
{
prgams(msg,
"template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")"
"{const int Serial = __LINE__;");
const int Serial = -1;
}
Более простым решением было бы сохранить глобальную статическую переменную «местоположения ошибки».
#ifdef DEBUG
#define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++);
#else
#define trace_here(version) printf("{%lu}\n", version<<16|errloc++);
#endif
Или без printf .. Просто увеличивайте значение errloc каждый раз, когда пересекаете точку трассировки. Затем вы можете легко сопоставить значение со строкой / номером / версией, выдаваемой вашими отладочными сборками.
Вам нужно будет указать версию или номер сборки, потому что эти места ошибок могут измениться с любой сборкой.
Не работает, если вы не можете воспроизвести пути кода.
__FILE__ - это указатель на сегмент констант вашей программы. Если вы выведете разницу между этой и какой-либо другой константой, вы должны получить результат, не зависящий от любого перемещения и т. д.:
extern const char g_DebugAnchor;
#define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)
Затем вы можете сообщить об этом или объединить это каким-либо образом с номером строки и т. д. Средние биты FILE_STR_OFFSET, вероятно, наиболее интересны.
Вы думаете, что у пользователей возникнут проблемы с цитированием «файл + строка», но они смогут дать вам хэш без транспонирования цифр?