Каков синтаксис следующего определения c?

Следующий фрагмент взят из mac sdk signal.h:

#define sigemptyset(set)    (*(set) = 0, 0)

просто интересно, что делает , 0)?

Я не думаю, что это соответствующая реализация. POSIX говорит, что это должна быть функция с прототипом int sigemptyset(sigset_t *set);. При использовании макросов они также должны проверять тип аргумента и предоставлять реализацию функции.

PSkocik 13.02.2023 16:11

@PSkocik: прототип функции присутствует в заголовочном файле и реализован в библиотеке, макрос допускает встроенное расширение, жертвуя проверкой типов, чтобы сократить несколько циклов.

chqrlie 13.02.2023 16:18

@chqrlie Проверка типов с помощью *(sigset_t*){set} была бы тривиальной для более новых C, у которых есть составные литералы. Можно сделать и с древними функциями C: *(0?(sigset_t*)0:(set)). Для codegen макрос, конечно, лучше, чем вызов функции для такой тривиальной вещи, но ненужные отклонения от стандарта меня немного раздражают (что иронично, потому что я даже не очень люблю стандарты). В любом случае, хороший ответ. +1

PSkocik 13.02.2023 16:29

@PSkocik: интересные способы проверки типов в макросах без множественной оценки и расширений выражений операторов!

chqrlie 13.02.2023 16:38
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
87
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Макрос расширяется до выражения с запятой: левый операнд, оцениваемый первым, устанавливает объект, на который указывает set, на 0, затем оценивается правый операнд, и его значение является значением всего выражения, следовательно: 0.

Другими словами, макрос ведет себя как функция, которая всегда завершается успешно, на успех указывает возвращаемое значение 0.

За исключением проверки типа, макрос эквивалентен:

#include <signal.h>

int sigemptyset(sigset_t *set) {
    *set = 0;
    return 0;
}

Обратите внимание, что заголовочный файл <signal.h> также содержит прототип этой функции:

int sigemptyset(sigset_t *);

В вашем коде вызов sigemptyset(&sigset) вызывает макрос, но вы можете вызвать ссылку на библиотечную функцию, написав (sigemptyset)(&sigset) или взяв указатель на функцию. Макрос допускает встроенное расширение без изменения прототипа. clang может выполнять встроенное расширение во время компоновки для небольших функций, но не для функций, определенных внутри динамических библиотек.

Тот же трюк используется для других функций в заголовочном файле, для которых , 0) необходим, чтобы выражение оценивалось как 0 с типом int:

#define sigaddset(set, signo)   (*(set) |= __sigbits(signo), 0)
#define sigdelset(set, signo)   (*(set) &= ~__sigbits(signo), 0)
#define sigemptyset(set)        (*(set) = 0, 0)
#define sigfillset(set)         (*(set) = ~(sigset_t)0, 0)

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

Bodo 13.02.2023 16:07

Тот же шаблон действительно используется для других макросов в <signal.h>, и использование , 0) приводит к тому, что выражение оценивается как 0 с типом int без приведения. sigset определяется как __uint32_t, определение макроса как #define sigemptyset(set) (*(set) = 0) будет иметь тип unsigned, а определение его как #define sigemptyset(set) ((int)(*(set) = 0)) не лучше, чем использование оператора запятой.

chqrlie 13.02.2023 16:09

В этом выражении

(*(set) = 0, 0)

используется оператор запятая.

Результат выражения равен 0.

В качестве побочного эффекта объекту, на который указывает указатель set, присваивается значение 0.

Из стандарта C (оператор запятой 6.5.17)

2 Левый операнд оператора запятой оценивается как пустота выражение; существует точка последовательности между его оценкой и тем, что правого операнда. Затем оценивается правый операнд; результат имеет свой тип и значение.

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