Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
при чтении Plauger Стандартная библиотека для C (1992) Вы будете видеть, что <stdio.h>
заголовку позволяют обеспечить getchar()
и getc()
как подобные функции макросы (со специальным разрешением для getc()
для оценки его аргумента указателя файла несколько раз!). Однако, даже если это обеспечивает макросы, реализация также обязана к provid фактическим функциям, которые делают то же задание, прежде всего так, чтобы можно было получить доступ к указателю функции, названному getchar()
или getc()
и передача это к другим функциям.
таким образом, путем выполнения:
#include <stdio.h>
#undef getchar
extern int some_function(int (*)(void));
int core_function(void)
{
int c = some_function(getchar);
return(c);
}
, Как записано, эти core_function()
довольно бессмысленно, но это иллюстрирует тезис. Можно сделать то же самое с isxxxx()
макросы в [1 112] также, например.
Обычно, Вы не хотите делать это - Вы обычно не хотите удалять макроопределение. Но при необходимости в реальной функции можно овладеть ею. Люди, которые обеспечивают библиотеки, могут эмулировать функциональность стандартной библиотеки для C успешно.
Также примечание, которое - одна из причин, редко необходимо использовать явное #undef
то, потому что можно вызвать функцию вместо макроса путем записи:
int c = (getchar)();
, поскольку маркер после getchar
не (
, это не вызов подобного функции макроса, таким образом, это должна быть ссылка на функцию. Точно так же первый пример выше, скомпилировал бы и работал бы правильно даже без #undef
.
при реализации собственной функции с макро-переопределением можно использовать это успешно, хотя это могло бы немного сбивать с толку, если не объяснено.
/* function.h */
…
extern int function(int c);
extern int other_function(int c, FILE *fp);
#define function(c) other_function(c, stdout);
…
/* function.c */
…
/* Provide function despite macro override */
int (function)(int c)
{
return function(c, stdout);
}
функциональная строка определения не вызывает макрос, потому что маркер после function
не (
. return
строка действительно вызывает макрос.
Макросы часто используются для генерации объема кода. Это часто - симпатичное локализованное использование, и это безопасно к #undef
любые макросы помощника в конце конкретного заголовка для предотвращения столкновений имени поэтому, только фактический сгенерированный код импортируется в другое место, и макросы, используемые, чтобы сгенерировать код, не делают.
Редактирование/: Как пример, я использовал это для генерации структур для меня. Следующее является выборкой из фактического проекта:
#define MYLIB_MAKE_PC_PROVIDER(name) \
struct PcApi##name { \
many members …
};
MYLIB_MAKE_PC_PROVIDER(SA)
MYLIB_MAKE_PC_PROVIDER(SSA)
MYLIB_MAKE_PC_PROVIDER(AF)
#undef MYLIB_MAKE_PC_PROVIDER
Я только использую его, когда макрос в #included
файл вмешивается в одну из моих функций (например, это имеет то же имя). Затем я #undef
макрос, таким образом, я могу использовать свою собственную функцию.
Поскольку препроцессор #define
с - все в одном глобальном пространстве имен, для конфликтов пространства имен легко закончиться, особенно при пользовании сторонними библиотеками. Например, если бы Вы хотели создать функцию, названную OpenFile
, то она не могла бы скомпилировать правильно, потому что заголовочный файл <windows.h>
определяет маркер OpenFile
для отображения или на OpenFileA
или на OpenFileW
(в зависимости от того, если UNICODE
определяется или не). Правильное решение к #undef
OpenFile
прежде, чем определить Вашу функцию.
Хотя я думаю, что Jonathan Leffler дал Вам правильный ответ. Вот очень редкий случай, где я использую #undef. Обычно макрос должен быть допускающим повторное использование во многих функциях; вот почему Вы определяете его наверху файла или в заголовочном файле. Но иногда у Вас есть некоторый повторяющийся код в функции, которая может быть сокращена с макросом.
int foo(int x, int y)
{
#define OUT_OF_RANGE(v, vlower, vupper) \
if (v < vlower) {v = vlower; goto EXIT;} \
else if (v > vupper) {v = vupper; goto EXIT;}
/* do some calcs */
x += (x + y)/2;
OUT_OF_RANGE(x, 0, 100);
y += (x - y)/2;
OUT_OF_RANGE(y, -10, 50);
/* do some more calcs and range checks*/
...
EXIT:
/* undefine OUT_OF_RANGE, because we don't need it anymore */
#undef OUT_OF_RANGE
...
return x;
}
, Чтобы показать читателю, что этот макрос только полезен в функции, это не определено в конце. Я не хочу поощрять любого использовать такие hackish макросы. Но если Вы имеете к, #undef их в конце.
это обычная практика для защиты от кого-то #define-ing макрос с тем же именем как функция? Или это - действительно больше образца, который не произошел бы в действительности? (EG, никто в его праве, неправильный ни безумный ум должен переписывать getchar (), таким образом, это не должно подходить.)
И то и другое. Хороший код не потребует использования #undef
, но существует много плохого кода там, необходимо работать с. #undef
может оказаться неоценимым, когда кто-то вытягивает прием как #define bool int
.
В дополнение к решению проблем с макросами, загрязняющими глобальное пространство имен, другое использование #undef
является ситуацией, где макрос мог бы потребоваться, чтобы иметь другое поведение в различных местах. Это не действительно общий сценарий, но пара, которые приходят на ум:
assert
макрос может иметь, это - определение, измененное посреди единицы компиляции для случая, где Вы могли бы хотеть выполнить отладку на некоторой части Вашего кода, но не других. В дополнение к assert
самостоятельно необходимость быть #undef
'редактор, чтобы сделать это, NDEBUG
макрос должен быть переопределен для реконфигурирования желаемого поведения assert
, я видел технику, используемую, чтобы гарантировать, что globals определяются точно однажды при помощи макроса для объявления переменных как extern
, но макрос не был бы переопределен ни к чему для единственного случая, где заголовок/объявления используется для определения переменных.
Что-то как (я не говорю, это - обязательно хорошая техника, всего один я видел в дикой природе):
/* globals.h */
/* ------------------------------------------------------ */
#undef GLOBAL
#ifdef DEFINE_GLOBALS
#define GLOBAL
#else
#define GLOBAL extern
#endif
GLOBAL int g_x;
GLOBAL char* g_name;
/* ------------------------------------------------------ */
/* globals.c */
/* ------------------------------------------------------ */
#include "some_master_header_that_happens_to_include_globals.h"
/* define the globals here (and only here) using globals.h */
#define DEFINE_GLOBALS
#include "globals.h"
/* ------------------------------------------------------ */
средство отслеживания памяти, которое я использую, определяет свои собственные новые/удаленные макросы для отслеживания информации о файле/строке. этот макрос повреждает SC ++ L.
#pragma push_macro( "new" )
#undef new
#include <vector>
#pragma pop_macro( "new" )
Относительно Вашего более конкретного вопроса: пространства имен часто emul; ated в C путем добавления префикса библиотечных функций идентификатор.
Вслепую undefing макросы собирается добавить беспорядок, уменьшить пригодность для обслуживания, и может повредить вещи, которые полагаются на исходное поведение. Если Вы были вынуждены, по крайней мере, используйте нажатие/поп еще для сохранения исходного поведения везде.