Реализация OSX main() и конфликтующих типов данных с POSIX getopt() в C?

Я нашел специфичное для системы определение и рекомендуемую практику использования main() трудно задокументированных в контексте POSIX getopt() в OSX/Darwin, например, как показано в этом небольшом тесте, который я написал:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main (int argc, const char *argv[])//this is *not* MY "prototype" of main - it is OSX!
{
    int   opt = 0;    
    int ch;
    char *cvalue = NULL;

    while ((ch = getopt (argc, argv, "d:")) != -1)
        switch (ch){
            case 'd':
                cvalue = optarg;
                opt = 1;
                break;
            case '?':
                if (optopt == 'd')
                     printf ("Option -%c requires an argument.\n", optopt);
                break;
            default:
                abort();
        }
    if(opt)printf("optarg = %s\n", optarg);
    return 0;
}

Компиляторы выдают следующие, довольно пугающие предупреждения:

gcc:

test.c: In function ‘main’:
test.c:15: warning: passing argument 2 of ‘getopt’ from incompatible pointer type

лязг:

test.c:15:32: warning: passing 'const char **' to parameter of type 'char *const *'
  discards qualifiers in nested pointer types [-Wincompatible-pointer-types]
while ((ch = getopt (argc, argv, "d:")) != -1)
                           ^~~~
 /usr/include/unistd.h:548:31: note: passing argument to parameter here
 int  getopt(int, char * const [], const char *) __DARWIN_ALIAS(getopt);
                              ^

Насколько мне известно, указатели char на неизменяемые массивы действительно несовместимы с неизменяемыми указателями на массивы символов. Я мало что могу сделать, если только не изменю определение main(), чтобы предоставить аргументы, как того требует POSIX getopt():

int main(int argc, char *const argv [] ){ ... }

или в соответствии со стандартом C (как определено в разделе 5.1.2.2.1 проекта стандарта C11 n1570) и описано в этом сообщении SO:

int main(int argc, char *argv[] ){ ... }

Это заглушает предупреждения компилятора, но заставляет задуматься: хотя один и тот же производитель реализует и C, и POSIX, разветвляется от их прототипа main(), который, по-видимому, конфликтует с их размещенной средой реализация POSIX C создает впечатление решения проблемы.

Поскольку я разрабатываю набор инструментов командной строки для UNIX в OSX, все из которых должны надежно перенаправлять, передавать, оставаться интерактивными< /em>, использовать файлы и т. д. в довольно сложных цепочках и критических условиях, мне нужно немного глубже понять, по какой причине OSX main() должен принимать такие типы аргументов. Кто-нибудь работал с этой конкретной реализацией main(), и какова безопасная процедура решения описанной проблемы в OSX/Darwin, не вызывающая риска UB или иного нарушения функциональности? Это то, к чему меня привели мои усилия - либо в конфликте с системой, либо со стандартом C. Заранее спасибо.


person user3078414    schedule 10.06.2016    source источник
comment
Ваш прототип для main() неверен. Предполагается, что это int main (int argc, char *argv[]) или эквивалентно int main (int argc, char **argv). Обратите внимание на отсутствие const. См. проект стандарта c11 n1570: 5.1.2.2.1 Запуск программы 2. Если они объявлены, параметры основной функции должны подчиняться следующим ограничениям: [...] — параметры argc и argv и строки, на которые указывают массивом argv должны быть изменены программой и сохранять свои последние сохраненные значения между запуском программы и завершением программы. Должны быть изменены.   -  person EOF    schedule 10.06.2016
comment
Спасибо за добрый комментарий, @EOF. Возможно, вы упустили из виду, что я не изобрел дурацкий доморощенный прототип main(), а использовал прототип OSX main(), @EOF. Я благодарен за то, что вы указали мне на тот же стандарт C, который я также цитирую в своем вопросе. Если коротко: то ли у меня конфликт с системой, то ли со стандартом - надеюсь есть решение - вот о чем мой вопрос. Тем не менее спасибо.   -  person user3078414    schedule 10.06.2016
comment
Интересно, почему объявлено, что getopt() принимает массив модифицируемых строк - зачем ему вообще нужно писать в них?   -  person Barmar    schedule 10.06.2016
comment
Нашел свой ответ здесь: lists.freebsd.org/pipermail/freebsd -хакеры/2011-февраль/   -  person Barmar    schedule 10.06.2016
comment
Что вы имеете в виду? Прототип OSX main? Я нигде не могу найти, что OSX определяет прототип для main. Единственное, что я могу найти в своей системе OSX, это int main(int argc, char **argv ) в /usr/include/tidy/tidy.h.   -  person Chris Dodd    schedule 10.06.2016
comment
Спасибо @Крис Додд. Вы можете найти его практически в любом примере кода для OSX. Даже если вы работали с любой версией Xcode Tools, будь то версия для командной строки или версия с графическим интерфейсом, int main(int argc, const char * argv[]) — это то, как выглядит сгенерированный системой шаблон в любой версии с 10+ лет. , или в любой документации Apple, связанной с main().   -  person user3078414    schedule 10.06.2016
comment
Я выполнил поиск в Интернете по запросу «пример OSX main C» и не могу найти ОДИН ОДИН пример, в котором используется const char — КАЖДЫЙ — это либо main(int, char **), либо main() (хотя есть некоторые сломанные с типом возврата void.)   -  person Chris Dodd    schedule 10.06.2016
comment
Спасибо за ваш вклад, @Chris Dodd. Я ни в коем случае не хочу противоречить вашему опыту или бросать вызов вашей доброй воле. Я бы сразу с вами согласился, потому что это логично. Я имею дело с вещами, изобретенными другими людьми и плохо задокументированными. Пожалуйста, посмотрите на это.   -  person user3078414    schedule 10.06.2016
comment
@ user3078414 Вы правы. Вы должны сообщить об ошибке в Apple.   -  person user3386109    schedule 10.06.2016


Ответы (1)


Это ваш код, значит, это ваш прототип. MacOS X может предлагать, как выглядит main, но вы не связаны этим. Все, что соответствует стандарту C, будет работать. Так что иди и добавь недостающий параметр.

person gnasher729    schedule 10.06.2016
comment
Спасибо @gnasher729. В моем коде я также выбрал вариант разветвления от прототипа OSX main(), потому что это самый простой способ избавиться от предупреждений компилятора. Я разместил этот вопрос в надежде получить больше информации от профессиональных людей, которые столкнулись с этой проблемой. Опубликованный тестовый пример - это то, как OSX предлагает делать это по книге. - person user3078414; 10.06.2016