Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. Помимо обычных методов отладчика и аспектно-ориентированного программирования, вы также можете вводить свои собственные инструментальные функции, используя опции командной строки gcc -finstrument-functions
. Вам нужно будет реализовать свои собственные функции __cyg_profile_func_enter()
и __cyg_profile_func_exit()
(объявите их как extern "C"
в C ++).
Они предоставляют средства для отслеживания того, какая функция была вызвана откуда. Однако интерфейс немного сложен в использовании, поскольку, например, адрес вызываемой функции и ее сайт вызова передаются вместо имени функции. Вы можете записать адреса, а затем извлечь соответствующие имена из таблицы символов, используя что-то вроде objdump --syms
или nm
, при условии, конечно, символы не были удалены из двоичные файлы.
Это может быть проще в использовании gdb
. YMMV. :)
Вы сказали «и при этом я не хочу трогать любой исходный файл» ... честную игру, если вы позволите сценарию сделать это за вас?
Запустите это на всех ваших файлах .cpp
sed 's/^{/{ENTRY/'
Чтобы преобразовать их в это:
void foo()
{ENTRY
// code here
}
Поместите это в заголовок, который может быть # # включен каждой единицей:
#define ENTRY EntryRaiiObject obj ## __LINE__ (__FUNCTION__);
struct EntryRaiiObject {
EntryRaiiObject(const char *f) : f_(f) { printf("Entered into %s", f_); }
~EntryRaiiObject() { printf("Exited from %s", f_); }
const char *f_;
};
Возможно, вам придется стать более изощренным со скриптом sed
. Вы также можете поместить макрос ENTRY в любое другое место, где хотите исследовать, например, в какую-то глубоко вложенную область видимости функции.
Используйте / Gh (Включить _penter Hook Function) и / GH (Включить _pexit Hook Function) переключатели компилятора (если вы можете скомпилировать источники конечно)
ПРИМЕЧАНИЕ: вы не сможете использовать эти макросы. См. Здесь («вам нужно получить адрес функции (в регистре EIP) и сравнить его с адресами в файле карты, которые могут быть сгенерированы компоновщиком (при условии, что перебазировка не произошла). быть очень медленным, хотя. ")
':input'
псевдоселектор? Я haven' t бывший в состоянии для нахождения ссылки для этого.
– julien_c
21 May 2013 в 15:39
':input'
псевдоселектор? Я haven' t бывший в состоянии для нахождения ссылки для этого.
– julien_c
21 May 2013 в 15:39
':input'
псевдоселектор? Я haven' t бывший в состоянии для нахождения ссылки для этого.
– julien_c
21 May 2013 в 15:39
':input'
псевдоселектор? Я haven' t бывший в состоянии для нахождения ссылки для этого.
– julien_c
21 May 2013 в 15:39
':input'
псевдоселектор? Я haven' t бывший в состоянии для нахождения ссылки для этого.
– julien_c
21 May 2013 в 15:39
Согласитесь с Уильямом, используйте gdb, чтобы увидеть поток времени выполнения.
Есть некоторый статический анализатор кода, который может сказать, какие функции вызывают, и может дать вам некоторый граф потока вызовов. Одним из инструментов является «Понимание C ++» (поддержка C / C ++), но это не бесплатно, я думаю. Но вы можете найти похожие инструменты.
Если вы используете gcc, флаг волшебного компилятора будет -g. Скомпилируйте с символами отладки, запустите программу под GDB и сгенерируйте трассировки стека. Вы также можете использовать ptrace, но, вероятно, намного проще просто использовать gdb.