Как установить указатель на память в NULL с помощью memset?

У меня есть структура

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*))

Но мне это не кажется правильным. Как правильно это сделать?


Поправка к вопросу - постановка радикально более сложного вопроса:

Вот что я пытаюсь сделать:

  • Два процесса, A и B
  • malloc p_my_t в A, B имеет N потоков и может получить к нему доступ
  • Начать удаление в A, но я не могу просто освободить его, так как потоки в B все еще могут его использовать.
  • Поэтому я вызываю функцию, передаю адрес p_my_t в B, чтобы установить его адрес в NULL в B, чтобы другие потоки в B больше не могли использовать
  • После обратного звонка от B я освобождаю память в A

NB: не существует стандартного способа управления распределением памяти через разделяемую память между процессами. Вам нужно будет довольно внимательно подумать о том, что происходит.

Вы пытаетесь установить p_my_t в NULL или вы пытаетесь установить адрес p_my_t в NULL?

Brian 30.12.2008 01:36

установить адрес p_my_t в NULL

dave 30.12.2008 01:43

@dave: вы не можете установить адрес p_my_t равным NULL (p_my_t - это имя ячейки памяти); вы можете установить значение p_my_t равным NULL, поэтому известно, что он никуда не указывает.

Jonathan Leffler 30.12.2008 03:20

@dave: также не следует использовать _t в качестве суффикса к именам переменных. Не рекомендуется использовать его для типов (POSIX резервирует имена типов, оканчивающиеся на _t, для использования в реализации), но совершенно сбивает с толку наличие переменной, заканчивающейся на _t.

Jonathan Leffler 30.12.2008 03:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
4
18 695
9

Ответы 9

Не используйте memset для инициализации нулевого указателя, так как это установит в памяти все нулевые биты, что не обязательно будет представлением нулевого указателя, просто сделайте следующее:

p_my_t = NULL;

или эквивалент:

p_my_t = 0;

Рекомендуемый код обычно напрямую использует 0 вместо NULL. 0 так же выразительно, как и NULL, и не требует макроса или его определения.

David Rodríguez - dribeas 30.12.2008 01:56

Кто рекомендует? 0 не так "выразительно", как NULL, i = NULL дает понять, что i является указателем, i = 0 - нет.

Robert Gamble 30.12.2008 02:17

В C++ NULL определяется как 0, поэтому "i = NULL дает понять, что i является указателем" компилятором не применяется. В C++ 0x есть nullptr, и это действительно применяется.

Chris Jester-Young 30.12.2008 02:51

Дело в том, что это дает понять человеку, читающему ваш код.

Robert Gamble 30.12.2008 02:57

Лучше использовать NULL. Он более читабелен, и при небольшой вероятности изменения определения NULL ваш код не сломается.

Ed S. 30.12.2008 03:28

Я согласен с использованием NULL, но определение NULL не изменится. Стандарт требует, чтобы он был равен 0 (хотя это может не соответствовать установке всех битов в ноль, как указал Роберт Гэмбл)

jalf 30.12.2008 06:08

Стандарт гарантирует, что 0 будет преобразован в правильный битовый шаблон для нулевого указателя. Он ничего не говорит о NULL. NULL нужен только для обратной совместимости с кодом C.

Ferruccio 30.12.2008 06:32

@Ferruccio: Не будь глупым, если NULL определен как 0, тогда i = NULL будет преобразован препроцессором в i = 0 с той же гарантией, как если бы он был записан как i = 0 для начала.

Robert Gamble 30.12.2008 06:36

Обновлен ответ, чтобы включить обе версии.

Robert Gamble 30.12.2008 06:39

Набор памяти и неинициализированная статическая / глобальная переменная для NULL стали настолько распространенными, что любые новые архитектуры не осмелятся нарушить их.

Joshua 30.12.2008 06:42

@jalf: Я согласен с тем, что NULL вряд ли изменится, но это напоминает мне знаменитую цитату из руководства Xerox Fortran при обсуждении преимуществ использования оператора DATA (который аналогичен использованию макроса препроцессора):

Robert Gamble 30.12.2008 06:43

"Вместо того, чтобы ссылаться на PI как на 3,141592653589797, при каждом появлении переменной PI может быть присвоено это значение с помощью оператора DATA и использоваться вместо более длинной формы константы. Это также упрощает модификацию программы в случае изменения значения PI . "

Robert Gamble 30.12.2008 06:43

@Joshua: 1) По моему опыту, использование memset для инициализации переменных указателя не является обычным, и 2) неинициализированные статические / глобальные переменные указателя гарантированно инициализируются значением NULL в C, я предполагаю, что то же самое верно и в C++ .

Robert Gamble 30.12.2008 06:46

Почему голосование против? Хотя бы объясни, что не так с ответом.

Robert Gamble 30.12.2008 06:50

я бы сказал, что ни NULL, ни 0 лучше. баллы могут быть сделаны для любого из них. некоторые люди предпочитают 0, некоторые предпочитают NULL. и да, неинициализированное статическое хранилище также инициализируется NULL в C++, и не все биты 0 необходимы.

Johannes Schaub - litb 30.12.2008 08:40

Страуструп не использует NULL. И если вы собираетесь использовать макрос, как он указывает, зачем вам использовать NULL вместо ожидаемого nullptr ???

ApplePieIsGood 30.12.2008 18:37

Аргументы в пользу использования NULL здесь уже были хорошо представлены. Суть в том, что NULL и 0 работают на всех платформах Cегодня, нет ничего плохого ни в одной из них, ваш отрицательный голос ничтожен.

Robert Gamble 30.12.2008 18:59

Проблема с неиспользованием более выразительной формы, чем 0, заключается в том, что человеку, который должен поддерживать код, требуется больше усилий, чтобы понять использование. Вы устанавливаете число, указатель, символ и т. д. На 0? Теперь nullptr кажется победой.

Greg Domjan 31.12.2008 06:32

Что именно ты пытаешься сделать? p_my_t уже является указателем, но вы не выделили для него память. Если вы хотите установить указатель на NULL, просто выполните

p_my_t = NULL;

Попытка разыменовать этот указатель приведет к ошибке сегментации (или нарушению доступа в Windows).

Как только указатель действительно указывает на что-то (например, через malloc() или путем присвоения ему адреса struct my_T), вы можете правильно memset():

memset(p_my_t, 0, sizeof(struct my_T));

Это обнулит всю структуру, установив все поля в ноль.

спасибо, добавление комментариев здесь имеет ограничения, поэтому, пожалуйста, посмотрите мой "ответный пост"

dave 30.12.2008 01:39

Спасибо, вот что я пытаюсь сделать

  • два процесса, A и B
  • malloc p_my_t в A, B имеет N потоков и может получить к нему доступ
  • начать удаление в A, но я не могу просто освободить его, так как потоки в B все еще могут использоваться.
  • поэтому я вызываю функцию, передаю адрес p_my_t в B, чтобы установить его адрес в NULL в B, чтобы другие потоки в B больше не могли использовать
  • После обратного звонка от B я освобождаю память в A

вам, вероятно, следует добавить эту информацию к своему вопросу или перефразировать ее - однако это звучит не так, как вы описали здесь. Если указатель не на разделяемую память, как он может быть разделен между процессами?

frankodwyer 30.12.2008 01:48

Я согласен, что это отличается от исходного вопроса. Вы должны поставить это как отдельный вопрос, поскольку ответ на вопрос, который вы фактически задали, будет просто p_my_t = NULL;

bsruth 30.12.2008 01:55

@dave: как два процесса разделяют память? Это совершенно другой вопрос, чем вы изначально задавали.

Jonathan Leffler 30.12.2008 03:22

В вашем ответе (где-то в этом сообщении) говорится:

Thanks, here is what I an trying to do

  • two processes, A and B
  • malloc p_my_t in 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_t to 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

bsruth 30.12.2008 01:54

Рекомендуемый код для установки указателя на ноль - присвоение 0 (ноль). Bjarne Stroustrup делает это :) В любом случае это так же выразительно, как NULL и не зависит от определения макроса.

Обратите внимание, что NULL не является ключевым словом, оно не зарезервировано, и хотя переопределение могло бы сбить с толку, ничто не говорит о том, что не следует (больше, чем стиль). Сотрудник часто шутит о том, что в каком-то заголовке можно указать значение NULL, отличное от 0, просто чтобы посмотреть, как ведет себя код других людей.

В следующем стандарте будет более выразительное ключевое слово nullptr для идентификации нулевого указателя.

фактически, он фактически запрещает переопределение NULL. вам не разрешено использовать #undef NULL, потому что он зарезервирован после включения заголовка std, который его определяет.

Johannes Schaub - litb 30.12.2008 08:46

NULL лучше! В следующем стандарте C++ будет новый объект nullptr. Есть проблемы при использовании 0 (преобразование int в указатель), nullptr их решит. В gcc NULL определяется как __null. Как только nullptr станет стандартным, измените NULL с 0 на nullptr; все преимущества без изменений для вас.

deft_code 30.12.2008 22:14

Я думаю может ты хочешь

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

  • Разместите структуру в общей памяти.
  • Выделите ptr структуре в общей памяти.
  • Защитите доступ к ptr к структуре с помощью блокировки чтения / записи.
  • Процесс A должен получить блокировку WRITE для ptr при инициализации или аннулировании ptr и структуры.
  • Процесс B должен получить блокировку READ для ptr и проверить, что ptr действителен, прежде чем использовать структуру

Другие вопросы по теме