1

I have found the system specific definition and recommended usage practice of main() hardly documented in context of POSIX getopt() in OSX/Darwin, such as shown in this little test I wrote:

#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;
}

The compilers issue the following, rather intimidating warnings:

gcc:

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

clang:

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);
                              ^

AFAIK, char pointers to immutable arrays are indeed incompatible with immutable pointers to character arrays. There is not much I can do unless changing the main() definition to supply arguments as required by POSIX getopt():

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

or according to the C standard (as defined in section 5.1.2.2.1 of C11 draft standard n1570) and described in this SO post:

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

This silences the compiler warnings, but makes me wonder: although same manufacturer implements both C and POSIX, forking from their prototype of main() which seemingly conflicts with their hosted environment implementation of POSIX C gives an impression of solving the problem.

As I am developing a set of UNIX command line tools in OSX, all of which must reliably redirect, pipe, stay interactive, use files etc. in rather complex chains and critical conditions, I need a bit deeper understanding for what reason the OSX main() should take such argument types. Has someone worked with this specific implementation of main(), and which would the safe procedure of solving the described issue in OSX/Darwin, without inducing risks of UB or otherwise compromised functionality? This is as far as my efforts have brought me - either in conflict with the system, or with the C standard. Thanks in advance.

Community
  • 1
  • 1
user3078414
  • 1,942
  • 2
  • 16
  • 24
  • 2
    Your prototype for `main()` is incorrect. It is supposed to be `int main (int argc, char *argv[])`, or equivalently `int main (int argc, char **argv)`. Note the lack of `const`. See c11 draft standard n1570: *5.1.2.2.1 Program startup 2 If they are declared, the parameters to the main function shall obey the following constraints: [...]— The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.* **Shall be modifiable**. – EOF Jun 10 '16 at 15:21
  • Thanks for your kind comment, @EOF. It might have skipped your attention that I haven't invented a goofy "homebrew" `main()` "prototype", but used the OSX prototype of `main()`, @EOF. I'm grateful for your pointing me at the same C standard I'm also quoting in my question. To put it short: I'm either in conflict with the system or with the standard - I hope there is a solution - that's what my question is about. Thanks, nevertheless. – user3078414 Jun 10 '16 at 16:00
  • I wonder why `getopt()` is declared to take an array of modifiable strings -- why would it ever need to write to them? – Barmar Jun 10 '16 at 16:03
  • 1
    Found my answer here: https://lists.freebsd.org/pipermail/freebsd-hackers/2011-February/034407.html – Barmar Jun 10 '16 at 16:06
  • What do you mean "The OSX prototype of main"? I can't find anywhere that OSX defines a prototype for main. The only one I can find on my OSX system is `int main(int argc, char **argv )` in /usr/include/tidy/tidy.h – Chris Dodd Jun 10 '16 at 16:07
  • Thanks @Chris Dodd. In practically any example code for OSX you can find it. Even if you worked with any version of *Xcode Tools*, be it command line or GUI version, `int main(int argc, const char * argv[])` is what the **system** generated template looks like, in any version since 10+ years, or in any Apple documentation involving `main()`. – user3078414 Jun 10 '16 at 16:20
  • I did a web search for 'OSX example main C', and can't find a SINGLE example that uses `const char` -- EVERY ONE is either `main(int, char **)` or `main()` (though there are some broken ones with a `void` return type.) – Chris Dodd Jun 10 '16 at 16:30
  • Thanks for your input, @Chris Dodd. By no means do I want to contradict your expertise or challenge your good will. I would have immediately agreed with you, because it is logical. I'm dealing with things other people have invented and poorly documented. Please be so kind to look at [this](https://books.google.hr/books?id=YpwXYYvxqwkC&pg=PA154&lpg=PA154&dq=osx+main(int+argc,+const+char+*argv%5B%5D)&source=bl&ots=mw-PbGbBoM&sig=HjGOaVfOYJ9YdWa7WjM2zePZZmM&hl=en&sa=X&ved=0ahUKEwjcr6CU8Z3NAhVGEJoKHT-SDt8Q6AEIRDAI#v=onepage&q=osx%20main(int%20argc%2C%20const%20char%20*argv%5B%5D)&f=false). – user3078414 Jun 10 '16 at 16:39
  • @user3078414 You are correct. You should report as a bug to Apple. – user3386109 Jun 10 '16 at 18:46

1 Answers1

0

It's your code, so it's your prototype. MacOS X may suggest what main looks like, but you're not bound by that. Anything conforming to the C standard will work. So go and add the missing parameter.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • Thanks @gnasher729. In *my* code I have also gone for the option of forking from _OSX_ prototype of `main()` because it's the easiest way to get rid of the compiler warnings. I posted this question hoping to get more information from professional people who have encountered this problem. The test example posted is how OSX would suggest doing it by the book. – user3078414 Jun 10 '16 at 16:25