У меня есть структура
typedef struct my_s {
int x;
...
} my_T;
my_t * p_my_t;
Я хочу установить адрес p_my_t на NULL, и до сих пор я пытался сделать это следующим образом:
memset (&p_my_t, 0, sizeof(my_t*))
Но мне это не кажется правильным. Как правильно это сделать?
Поправка к вопросу - постановка радикально более сложного вопроса:
Вот что я пытаюсь сделать:
NB: не существует стандартного способа управления распределением памяти через разделяемую память между процессами. Вам нужно будет довольно внимательно подумать о том, что происходит.
установить адрес p_my_t в NULL
@dave: вы не можете установить адрес p_my_t равным NULL (p_my_t - это имя ячейки памяти); вы можете установить значение p_my_t равным NULL, поэтому известно, что он никуда не указывает.
@dave: также не следует использовать _t в качестве суффикса к именам переменных. Не рекомендуется использовать его для типов (POSIX резервирует имена типов, оканчивающиеся на _t, для использования в реализации), но совершенно сбивает с толку наличие переменной, заканчивающейся на _t.





Не используйте memset для инициализации нулевого указателя, так как это установит в памяти все нулевые биты, что не обязательно будет представлением нулевого указателя, просто сделайте следующее:
p_my_t = NULL;
или эквивалент:
p_my_t = 0;
Рекомендуемый код обычно напрямую использует 0 вместо NULL. 0 так же выразительно, как и NULL, и не требует макроса или его определения.
Кто рекомендует? 0 не так "выразительно", как NULL, i = NULL дает понять, что i является указателем, i = 0 - нет.
В C++ NULL определяется как 0, поэтому "i = NULL дает понять, что i является указателем" компилятором не применяется. В C++ 0x есть nullptr, и это действительно применяется.
Дело в том, что это дает понять человеку, читающему ваш код.
Лучше использовать NULL. Он более читабелен, и при небольшой вероятности изменения определения NULL ваш код не сломается.
Я согласен с использованием NULL, но определение NULL не изменится. Стандарт требует, чтобы он был равен 0 (хотя это может не соответствовать установке всех битов в ноль, как указал Роберт Гэмбл)
Стандарт гарантирует, что 0 будет преобразован в правильный битовый шаблон для нулевого указателя. Он ничего не говорит о NULL. NULL нужен только для обратной совместимости с кодом C.
@Ferruccio: Не будь глупым, если NULL определен как 0, тогда i = NULL будет преобразован препроцессором в i = 0 с той же гарантией, как если бы он был записан как i = 0 для начала.
Обновлен ответ, чтобы включить обе версии.
Набор памяти и неинициализированная статическая / глобальная переменная для NULL стали настолько распространенными, что любые новые архитектуры не осмелятся нарушить их.
@jalf: Я согласен с тем, что NULL вряд ли изменится, но это напоминает мне знаменитую цитату из руководства Xerox Fortran при обсуждении преимуществ использования оператора DATA (который аналогичен использованию макроса препроцессора):
"Вместо того, чтобы ссылаться на PI как на 3,141592653589797, при каждом появлении переменной PI может быть присвоено это значение с помощью оператора DATA и использоваться вместо более длинной формы константы. Это также упрощает модификацию программы в случае изменения значения PI . "
@Joshua: 1) По моему опыту, использование memset для инициализации переменных указателя не является обычным, и 2) неинициализированные статические / глобальные переменные указателя гарантированно инициализируются значением NULL в C, я предполагаю, что то же самое верно и в C++ .
Почему голосование против? Хотя бы объясни, что не так с ответом.
я бы сказал, что ни NULL, ни 0 лучше. баллы могут быть сделаны для любого из них. некоторые люди предпочитают 0, некоторые предпочитают NULL. и да, неинициализированное статическое хранилище также инициализируется NULL в C++, и не все биты 0 необходимы.
Страуструп не использует NULL. И если вы собираетесь использовать макрос, как он указывает, зачем вам использовать NULL вместо ожидаемого nullptr ???
Аргументы в пользу использования NULL здесь уже были хорошо представлены. Суть в том, что NULL и 0 работают на всех платформах Cегодня, нет ничего плохого ни в одной из них, ваш отрицательный голос ничтожен.
Проблема с неиспользованием более выразительной формы, чем 0, заключается в том, что человеку, который должен поддерживать код, требуется больше усилий, чтобы понять использование. Вы устанавливаете число, указатель, символ и т. д. На 0? Теперь nullptr кажется победой.
Что именно ты пытаешься сделать? p_my_t уже является указателем, но вы не выделили для него память. Если вы хотите установить указатель на NULL, просто выполните
p_my_t = NULL;
Попытка разыменовать этот указатель приведет к ошибке сегментации (или нарушению доступа в Windows).
Как только указатель действительно указывает на что-то (например, через malloc() или путем присвоения ему адреса struct my_T), вы можете правильно memset():
memset(p_my_t, 0, sizeof(struct my_T));
Это обнулит всю структуру, установив все поля в ноль.
спасибо, добавление комментариев здесь имеет ограничения, поэтому, пожалуйста, посмотрите мой "ответный пост"
Спасибо, вот что я пытаюсь сделать
вам, вероятно, следует добавить эту информацию к своему вопросу или перефразировать ее - однако это звучит не так, как вы описали здесь. Если указатель не на разделяемую память, как он может быть разделен между процессами?
Я согласен, что это отличается от исходного вопроса. Вы должны поставить это как отдельный вопрос, поскольку ответ на вопрос, который вы фактически задали, будет просто p_my_t = NULL;
@dave: как два процесса разделяют память? Это совершенно другой вопрос, чем вы изначально задавали.
В вашем ответе (где-то в этом сообщении) говорится:
Thanks, here is what I an trying to do
- two processes, A and B
- malloc
p_my_tin A, B has N threads and can access it- start deleting in A but I can not simply free it since threads in B may still using.
- so I call a function, pass address of
p_my_tto B to set its address to NULL in B so no others threads in B can use anymore- After call back from B, I then free memory in A
Вам нужна какая-то форма синхронизации между всеми вашими потоками и процессами. Я не уверен, как вы разделяете этот объект между процессами, но подозреваю, что вы используете разделяемую память.
Обычно я бы рекомендовал использовать класс общего указателя (например, класс Boost shared_ptr), но я не уверен, насколько хорошо это будет работать в этом сценарии. Возможно, вы захотите настроить свой класс так, чтобы он отслеживал свои собственные ссылки и мог использоваться с классом Boost intrusive_ptr.
Таким образом, процесс A может просто забыть об объекте, а когда процесс B завершится, экземпляр my_T узнает, что ссылок больше не осталось, и очистится.
Синхронизация вступает в игру здесь, когда my_T добавляет или удаляет ссылки внутри (так что вы не столкнетесь с неприятными условиями гонки, когда он думает, что он должен очистить себя, но на самом деле все еще используется).
Еще один подход, который имеет немного больше ощущения «клуджа», - это дать каждому экземпляру my_T флаг «действителен», чтобы все процессы / потоки, использующие его, знали, продолжать ли это делать.
Дополнительные сведения о различных классах указателей Boost см. В их документация.
Вы также можете использовать класс TR1 shared_ptr, который ранее был доступен в boost. Это позволит вам удалить указатель в B, не беспокоясь о том, что делает A. Подробнее о shared_ptr: boost.org/doc/libs/1_37_0/libs/smart_ptr/shared_ptr.htm
Рекомендуемый код для установки указателя на ноль - присвоение 0 (ноль). Bjarne Stroustrup делает это :) В любом случае это так же выразительно, как NULL и не зависит от определения макроса.
Обратите внимание, что NULL не является ключевым словом, оно не зарезервировано, и хотя переопределение могло бы сбить с толку, ничто не говорит о том, что не следует (больше, чем стиль). Сотрудник часто шутит о том, что в каком-то заголовке можно указать значение NULL, отличное от 0, просто чтобы посмотреть, как ведет себя код других людей.
В следующем стандарте будет более выразительное ключевое слово nullptr для идентификации нулевого указателя.
фактически, он фактически запрещает переопределение NULL. вам не разрешено использовать #undef NULL, потому что он зарезервирован после включения заголовка std, который его определяет.
NULL лучше! В следующем стандарте C++ будет новый объект nullptr. Есть проблемы при использовании 0 (преобразование int в указатель), nullptr их решит. В gcc NULL определяется как __null. Как только nullptr станет стандартным, измените NULL с 0 на nullptr; все преимущества без изменений для вас.
Я думаю может ты хочешь
extern void set_t_pointer_to_null(my_T *pp);
и позвони
set_t_pointer_to_null(&p_my_t);
где
void set_t_pointer_to_null(my_T *pp) { *pp = NULL; }
Я не уверен, что для этого стоит определять функцию, но я думаю, что это отвечает на вопрос, который вы пытаетесь задать.
Читая ваши многопоточные комментарии, я должен сказать, что существует безопасная последовательность кода нет для выполнения вашей задачи. Вам придется сделать шаг назад и пересмотреть свой алгоритм.
Если я правильно понял, memset не решит вашу проблему. Если A и B - это отдельные процессы, то p_my_t в процессе A будет отличаться от p_my_t в процессе B. Вы просто не можете передавать указатель между разными процессами. Я предполагаю, что вы используете какой-то механизм IPC, чтобы синхронизировать два ваших процесса (например, очереди сообщений), и просто использовать p_my_t = NULL вместо memset.
Согласно вашему обновлению, мне кажется, что на самом деле вы пытаетесь защитить доступ к ресурсу, что означает, что вы должны использовать блокировку чтения / записи, которая используется совместно между процессами для защиты ptr этого ресурса, и протестировать ptr перед использованием.
Вы пытаетесь установить p_my_t в NULL или вы пытаетесь установить адрес p_my_t в NULL?