Безопасно ли предположить, что pid_t всегда имеет тип int (как определено в стандарте)?

Я хотел атомарно сравнить и поменять местами переменную pid_t. Я читал в стандарте, что это тип int.

Я знаю, что atomic_compare_exchange_strong_explicit() может управлять вещами самостоятельно. Все, что мне нужно сделать, это установить тип как _Atomic(pid_t).

Но поскольку я работаю над macOS и хочу сделать ее совместимой со старой библиотекой OSX, а именно libkern/OSAtomic.h, мне нужно знать тип и размер типа для CAS.

Как и в случае с size_t, я мог бы просто сделать так:

#   ifdef __LP64__
#       define CAS_size_t(old, new, mem) \
        OSAtomicCompareAndSwap64((int64_t) (*old), (int64_t) (new), (volatile int64_t *) (mem))
#   else
#       define CAS_size_t(old, new, mem) \
        OSAtomicCompareAndSwap32((int32_t) (*old), (int32_t) (new), (volatile int32_t *) (mem))
#   endif

Но в случае pid_t я не уверен, потому что даже если __LP64__ не определено, то это может быть int64_t, int32_t, int16_t или что-то в этом роде?

Все, что вы знаете, это то, что это некоторый целочисленный тип со знаком, способный представлять идентификатор процесса. У вас могут быть случаи #if, основанные на значении sizeof(pid_t), и выдавать ошибку компиляции в случае #else.

Thomas Jager 28.05.2019 17:26

Вероятно, sizeof(pid_t) не будет работать в условии #if right. Он предварительно обработан?

Mihir Luthra 28.05.2019 17:27

Точно, я забыл, что

Thomas Jager 28.05.2019 17:29

У вас есть С11? Вы можете пойти с решением _Generic. Или просто передайте sizeof(var) функции... Почему бы не просто #define CAS_size_t(old, new, mem) do { if (sizeof(*old) == sizeof(int64_t)) { call_64(...); } else if (sizeof(*old) == sizeof(int32_t)) { call_32(...); } else assert(0); } while(0). В любом случае проверка, вероятно, будет оптимизирована компилятором.

KamilCuk 28.05.2019 17:29

Что ж, для C11 stdatomic.h уже является решением, но главная цель — сделать его и обратно совместимым. Вероятно, мне нужно придерживаться функции в этом случае. Также спасибо, что поделились этой _Generic вещью, я не знал об этом.

Mihir Luthra 28.05.2019 17:34

@KamilCuk, ты прав. Спасибо и за это, раньше вообще не приходило в голову.

Mihir Luthra 28.05.2019 17:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
346
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Просто проверьте размер значения внутри макроса:

#define OSAtomicCompareAndSwap(old, new, mem)  do{ \
     if (sizeof(*old) == sizeof(int32_t)) { \
        OSAtomicCompareAndSwap32((int32_t)(*old), (int32_t) (new), (volatile int32_t *) (mem));  \
     } else if (sizeof(*old) == sizeof(int64_t)) { \
        OSAtomicCompareAndSwap64((int64_t)(*old), (int64_t) (new), (volatile int64_t *) (mem));  \
     } else assert(0); }while(0)

В любом случае проверки должны быть оптимизированы компилятором. Это не проверка типов (для этого нам понадобится C++-ish typeid), проверяется только размер.

Если вам нужно вернуть значение, если вы считаете, что вам нужно передать другую переменную:

#define OSAtomicCompareAndSwap(ret, old, new, mem)  do{ \
     if (sizeof(*old) == sizeof(int32_t)) { \
        ret = OSAtomicCompareAndSwap32((int32_t)(*old), (int32_t) (new), (volatile int32_t *) (mem));  \
     } else if (sizeof(*old) == sizeof(int64_t)) { \
        ret = OSAtomicCompareAndSwap64((int64_t)(*old), (int64_t) (new), (volatile int64_t *) (mem));  \
     } else assert(0); }while(0)

или экс. передать указатель на переменную, которая будет связана с memcpy результатом или чем-то подобным. Или вы можете использовать расширение gcc выражение оператора.

С выражением оператора, которое может выглядеть так:

#define OSAtomicCompareAndSwap(old, new, mem)  __extension__({ \
     int64_t ret = 0; \
     if (sizeof(*old) == sizeof(int32_t)) { \
        ret = OSAtomicCompareAndSwap32((int32_t)(*old), (int32_t) (new), (volatile int32_t *) (mem));  \
     } else if (sizeof(*old) == sizeof(int64_t)) { \
        ret = OSAtomicCompareAndSwap64((int64_t)(*old), (int64_t) (new), (volatile int64_t *) (mem));  \
     } else { \
          assert(0); \
     } \
     ret; \
})

Спасибо чувак. Это расширение statement expression наверняка мне очень поможет, приятно знать так много в одном посте.

Mihir Luthra 28.05.2019 18:02

вы должны определить макросы без завершающего ';' потому что вы бы написали ";" в любом случае после вызова макроса. В том виде, в котором он есть сейчас, это не будет компилироваться: if ( .. ) OSAtomicCompareAndSwap(old,new,mem);else ...

Ingo Leonhardt 28.05.2019 18:21

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