Что делает двойное подчеркивание (__ константа), означают в C?

У меня есть программа, названная timeout, который делает это - записанный в C, первоначально в 1989, но обновляемый периодически с тех пор.

<час> Обновление: этому коду не удается скомпилировать на MacOS X, потому что SIGRTMIN не определяется и перестал работать к тайм-ауту при выполнении на MacOS X, потому что эти signal() функция там возобновляется wait() после времен аварийного сигнала - который не является необходимым поведением. У меня есть новая версия timeout.c, который имеет дело с обеими этими проблемами (использующий sigaction() вместо signal()). Как прежде, свяжитесь со мной для 10K gzipped файл tar с исходным кодом и страницей руководства (см. мой профиль). <час>
/*
@(#)File:           $RCSfile: timeout.c,v $
@(#)Version:        $Revision: 4.6 $
@(#)Last changed:   $Date: 2007/03/01 22:23:02 $
@(#)Purpose:        Run command with timeout monitor
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 1989,1997,2003,2005-07
*/

#define _POSIX_SOURCE       /* Enable kill() in <unistd.h> on Solaris 7 */
#define _XOPEN_SOURCE 500

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "stderr.h"

#define CHILD       0
#define FORKFAIL    -1

static const char usestr[] = "[-vV] -t time [-s signal] cmd [arg ...]";

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_timeout_c[] = "@(#)$Id: timeout.c,v 4.6 2007/03/01 22:23:02 jleffler Exp $";
#endif /* lint */

static void catcher(int signum)
{
    return;
}

int main(int argc, char **argv)
{
    pid_t   pid;
    int     tm_out;
    int     kill_signal;
    pid_t   corpse;
    int     status;
    int     opt;
    int     vflag = 0;

    err_setarg0(argv[0]);

    opterr = 0;
    tm_out = 0;
    kill_signal = SIGTERM;
    while ((opt = getopt(argc, argv, "vVt:s:")) != -1)
    {
        switch(opt)
        {
        case 'V':
            err_version("TIMEOUT", &"@(#)$Revision: 4.6 $ ($Date: 2007/03/01 22:23:02 $)"[4]);
            break;
        case 's':
            kill_signal = atoi(optarg);
            if (kill_signal <= 0 || kill_signal >= SIGRTMIN)
                err_error("signal number must be between 1 and %d\n", SIGRTMIN - 1);
            break;
        case 't':
            tm_out = atoi(optarg);
            if (tm_out <= 0)
                err_error("time must be greater than zero (%s)\n", optarg);
            break;
        case 'v':
            vflag = 1;
            break;
        default:
            err_usage(usestr);
            break;
        }
    }

    if (optind >= argc || tm_out == 0)
        err_usage(usestr);

    if ((pid = fork()) == FORKFAIL)
        err_syserr("failed to fork\n");
    else if (pid == CHILD)
    {
        execvp(argv[optind], &argv[optind]);
        err_syserr("failed to exec command %s\n", argv[optind]);
    }

    /* Must be parent -- wait for child to die */
    if (vflag)
        err_remark("time %d, signal %d, child PID %u\n", tm_out, kill_signal, (unsigned)pid);
    signal(SIGALRM, catcher);
    alarm((unsigned int)tm_out);
    while ((corpse = wait(&status)) != pid && errno != ECHILD)
    {
        if (errno == EINTR)
        {
            /* Timed out -- kill child */
            if (vflag)
                err_remark("timed out - send signal %d to process %d\n", (int)kill_signal, (int)pid);
            if (kill(pid, kill_signal) != 0)
                err_syserr("sending signal %d to PID %d - ", kill_signal, pid);
            corpse = wait(&status);
            break;
        }
    }

    alarm(0);
    if (vflag)
    {
        if (corpse == (pid_t) -1)
            err_syserr("no valid PID from waiting - ");
        else
            err_remark("child PID %u status 0x%04X\n", (unsigned)corpse, (unsigned)status);
    }

    if (corpse != pid)
        status = 2; /* Dunno what happened! */
    else if (WIFEXITED(status))
        status = WEXITSTATUS(status);
    else if (WIFSIGNALED(status))
        status = WTERMSIG(status);
    else
        status = 2; /* Dunno what happened! */

    return(status);
}

, Если Вы хотите 'официальный' код для 'stderr.h' и 'stderr.c', свяжитесь со мной (см. мой профиль).

48
задан sepp2k 8 March 2019 в 20:45
поделиться

4 ответа

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

Дано:

extern int ether_hostton (__const char *__hostname, struct ether_addr *__addr)
__THROW;

Нотация __ const предназначена для учета возможности (что маловероятно) того, что компилятор использует этот код with поддерживает обозначения прототипов, но не имеет правильного понимания стандартного ключевого слова C89 const . Макросы autoconf могут по-прежнему проверять, есть ли у компилятора работающая поддержка const ; этот код можно использовать со сломанным компилятором, не имеющим такой поддержки.

Использование __ hostname и __ addr является мерой защиты для вас, пользователя заголовка. Если вы компилируете с GCC и параметром -Wshadow , компилятор предупредит вас, когда какие-либо локальные переменные затеняют глобальную переменную. Если бы функция использовала только имя хоста вместо __ имя хоста , и если бы у вас была функция с именем имя хоста () , то было бы затенение. Использование имен, зарезервированных для реализации, исключает конфликт с вашим законным кодом.

Использование __ THROW означает, что код при некоторых обстоятельствах может быть объявлен с какой-то «спецификацией выброса» . Это не стандартный C; это больше похоже на C ++. необязательно объявляет или определяет идентификаторы, перечисленные в связанных будущих направлениях библиотеки подпункт и идентификаторы, которые всегда зарезервированы либо для любого использования, либо для использования в качестве файла идентификаторы области.

- Все идентификаторы, начинающиеся с подчеркивания и либо прописной буквы, либо другой подчеркивание всегда зарезервировано для любого использования.

- Все идентификаторы, начинающиеся с символа подчеркивания, всегда зарезервированы для использования в качестве идентификаторов с областью видимости файла как в обычном, так и в пространстве имен тегов.

- Каждое имя макроса в любом из следующих подпунктов (включая будущую библиотеку Направления) зарезервирован для использования, как указано, если включен какой-либо из связанных с ним заголовков; если явно не указано иное (см. 7.1.4).

- Все идентификаторы с внешней связью в любом из следующих подпунктов (включая будущие направления библиотеки) всегда зарезервированы для использования в качестве идентификаторов с внешними ссылка. 154)

- Каждый идентификатор с областью действия файла, перечисленной в любом из следующих подпунктов (включая будущие направления библиотеки) зарезервировано для использования в качестве имени макроса и идентификатора с область файла в том же пространстве имен, если включен какой-либо из связанных с ней заголовков.

Никакие другие идентификаторы не зарезервированы. Если программа объявляет или определяет идентификатор в контекст, в котором он зарезервирован (кроме разрешенного 7.1.4), или определяет зарезервированный идентификатор в качестве имени макроса, поведение не определено.

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

Сноска 154) Список зарезервированных идентификаторов с внешней связью включает errno , math_errhandling , setjmp и va_end .


См. Также Каковы правила использования символа подчеркивания в идентификаторе C ++ ; многие из тех же правил применимы как к C, так и к C ++, хотя встроенное правило двойного подчеркивания присутствует только в C ++, как упоминалось в верхней части этого ответа.

70
ответ дан 26 November 2019 в 18:45
поделиться

Имена с двойным нижним подчеркиванием зарезервированы для использования реализацией. Это не обязательно означает, что они внутренние сами по себе, хотя часто они таковы.

Идея в том, что вам не разрешается использовать имена, начинающиеся с __ , поэтому реализация может свободно использовать их в таких местах, как расширения макросов, или в именах расширений синтаксиса (например, __ gcnew не является частью C ++, но Microsoft может добавить его в C ++ / CLI, будучи уверенным, что в существующем коде не должно быть чего-то вроде int __gcnew; , что остановило бы компиляцию).

Чтобы узнать, что означают эти конкретные расширения, например __ const , вам необходимо обратиться к документации для вашего конкретного компилятора / платформы. В данном конкретном случае

19
ответ дан 26 November 2019 в 18:45
поделиться

По соглашению в некоторых библиотеках это означает, что конкретный символ предназначен для внутреннего использования и не предназначен для того, чтобы быть частью общедоступного API библиотеки.

3
ответ дан 26 November 2019 в 18:45
поделиться

подчеркивание в __const означает, что это ключевое слово является расширением компилятора и его использование не является переносимым (ключевое слово const было добавлено в C в более поздней версии 89, я думаю). __THROW также является своего рода расширением, я предполагаю, что он определяется для некоторого __attribute __ (что-то), если используется gcc, но я не уверен в этом и слишком ленив, чтобы проверить. __Addr может означать все, что хотел программист, это просто имя.

2
ответ дан 26 November 2019 в 18:45
поделиться
Другие вопросы по тегам:

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