#undef-ing на практике?

Указатель NULL - это тот, который указывает на никуда. Когда вы разыскиваете указатель p, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p является нулевым указателем, местоположение, хранящееся в p, является nowhere, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception.

В общем, это потому, что что-то не было правильно инициализировано.

15
задан Jonathan Leffler 10 January 2015 в 03:52
поделиться

8 ответов

Что это делает

при чтении 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 строка действительно вызывает макрос.

15
ответ дан 1 December 2019 в 00:54
поделиться

Макросы часто используются для генерации объема кода. Это часто - симпатичное локализованное использование, и это безопасно к #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
14
ответ дан 1 December 2019 в 00:54
поделиться

Я только использую его, когда макрос в #included файл вмешивается в одну из моих функций (например, это имеет то же имя). Затем я #undef макрос, таким образом, я могу использовать свою собственную функцию.

2
ответ дан 1 December 2019 в 00:54
поделиться

Поскольку препроцессор #define с - все в одном глобальном пространстве имен, для конфликтов пространства имен легко закончиться, особенно при пользовании сторонними библиотеками. Например, если бы Вы хотели создать функцию, названную OpenFile, то она не могла бы скомпилировать правильно, потому что заголовочный файл <windows.h> определяет маркер OpenFile для отображения или на OpenFileA или на OpenFileW (в зависимости от того, если UNICODE определяется или не). Правильное решение к #undef OpenFile прежде, чем определить Вашу функцию.

6
ответ дан 1 December 2019 в 00:54
поделиться

Хотя я думаю, что 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 их в конце.

2
ответ дан 1 December 2019 в 00:54
поделиться

это обычная практика для защиты от кого-то #define-ing макрос с тем же именем как функция? Или это - действительно больше образца, который не произошел бы в действительности? (EG, никто в его праве, неправильный ни безумный ум должен переписывать getchar (), таким образом, это не должно подходить.)

И то и другое. Хороший код не потребует использования #undef, но существует много плохого кода там, необходимо работать с. #undef может оказаться неоценимым, когда кто-то вытягивает прием как #define bool int.

1
ответ дан 1 December 2019 в 00:54
поделиться

В дополнение к решению проблем с макросами, загрязняющими глобальное пространство имен, другое использование #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"

/* ------------------------------------------------------ */
1
ответ дан 1 December 2019 в 00:54
поделиться

Если макрос может быть def'ed, должно быть средство к undef.

средство отслеживания памяти, которое я использую, определяет свои собственные новые/удаленные макросы для отслеживания информации о файле/строке. этот макрос повреждает SC ++ L.

#pragma push_macro( "new" )
#undef new
#include <vector>
#pragma pop_macro( "new" )

Относительно Вашего более конкретного вопроса: пространства имен часто emul; ated в C путем добавления префикса библиотечных функций идентификатор.

Вслепую undefing макросы собирается добавить беспорядок, уменьшить пригодность для обслуживания, и может повредить вещи, которые полагаются на исходное поведение. Если Вы были вынуждены, по крайней мере, используйте нажатие/поп еще для сохранения исходного поведения везде.

0
ответ дан 1 December 2019 в 00:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: