C++ - what's the default method of opening a file passed to main via *argv[]?



  • I'm a self-taught C++ programmer, and I stumbled across the second method of main(), being main(int argc, char *argv[]) of course.

    The first thing I did was create a small sample program that simply displayed the value of argc and all the values of argv[] that were passed to it. After experimenting with it a bit, I noticed that argv[0] is always the command line text used to execute my program, and the other argv values contain everything else that was passed to it. My question is, where can I go to learn more about the standard methods of passing programs arguments?

    I was interested about learning the following in particular:

    -How are parameters starting with tags such as -o, -f, -a, and so on usually handled?

    -I noticed that, if a file opens the program via a file extension associan, argv[1] contains the location of the file calling my program. How am I to know when argv[1] is a file location, and not a usual parameter? Should I check for C:\? I've just been checking for "-:\" (argv[1]+1 value is :, argv[2]+2 value is \), but my code looks very 'thrown together', and I figured that there HAS to be a more standard way of doing this sort of thing.

    Are there some flags thrown when a file opens the program that I should look for? This is what I've been working with:

     



    #include <iostream>
    #include <stdlib.h>

    #define DEFAULT_FILE "default.arg"

    using namespace std;

    void goodbyeMessage();

    int main(int argc, char *argv[]) {
    atexit(goodbyeMessage);
    FILE* openFile;
    cout << "Arg count: " << argc;
    printf("\n\nArguments:\n");
    for(int i=0;i<argc;i++) {
    printf("%d: %s\n", i, argv[i]);
    }
    cout << "\n\n\n";

    if (argc>1) if( (*(argv[1]+1)==':') && (*(argv[1]+2)=='\\') ) { //argv[1] is a file path
    cout << argv[1] << " is a file path!";
    //open file, load variables
    }
    else { //argv[1] is not a file path
    //open Default file, set default variables
    }
    return 0;
    }

    void goodbyeMessage() {
    cout << "Goodbye...!\n\n";
    system("PAUSE");
    }


  • -I noticed that, if a file opens the program via a file extension associan, argv[1] contains the location of the file calling my program. How am I to know when argv[1] is a file location, and not a usual parameter?

    Why do you care?



    As for the -f and such flags loop through argv (note argv[argc] should be set to null, the same as char ** env [main's third param])).


    for (int i = 0; i < argc; i++) {
      if (argv[i][0] == '-') {
        continue;
      }
      for (int j = 1; argv[i][j] != 0; j++) {
        //Deal with argv[i][j];
      }
    }
    


  • Do have a look at getopt() (it's POSIX C I think). There are also versions for cpp (http://www.math.utah.edu/docs/info/libg++_39.html) and some more fancy versions implemented as classes ( http://ulisse.elettra.trieste.it/services/doc/libg++/libg++.html#SEC83 )

     

    HTH,

    Greg 



  • @pyro789x said:

    I'm a self-taught
    C++ programmer, and I stumbled across the second method of main(),
    being main(int argc, char *argv[]) of course.



    The first thing I did was create a small sample program that simply
    displayed the value of argc and all the values of argv[] that were
    passed to it. After experimenting with it a bit, I noticed that argv[0]
    is always the command line text used to execute my program, and the
    other argv values contain everything else that was passed to it. My
    question is, where can I go to learn more about the standard methods of
    passing programs arguments?



    I was interested about learning the following in particular:



    -How are parameters starting with tags such as -o, -f, -a, and so on usually handled?

    Manually. (Well, there's a library function called getopt on some systems, but they've been handled in a while/case loop since time immemorial.)


    -I noticed that, if a file opens the program via a file extension
    associan, argv[1] contains the location of the file calling my program.
    How am I to know when argv[1] is a file location, and not a usual
    parameter?

    It's always a "usual parameter" - programs that can be associated with a file extension are expected to accept the file as the first/only argument on the command line in normal usage. 

    Should I check for C:? I've just been checking for "-:" (argv[1]+1 value is :, argv[2]+2 value is ), but my code looks very 'thrown together', and I figured that there HAS to be a more standard way of doing this sort of thing.

    If your program is designed to accept files via drag/drop or extension association, it should ALWAYS assume an argument is a filename unless it is e.g. a switch (begins with '/' or '-' usually, different programs have different conventions)

    Are there some flags thrown when a file opens the program that I should look for?

    No.

    Basically, you should always assume it's a filename unless there's a specific reason it's not, rather than checking for whether it is. Asking how to tell if it's a filename or a usual parameter is the wrong question - your "usual" parameters should be filenames, or you shouldn't be setting up a file extension association.



  • @Random832 said:

    It's always a "usual parameter" - programs that can be associated with a file extension are expected to accept the file as the first/only argument on the command line in normal usage.

    This isn't true (at least under Windows, since 3.1 or so).

    The file association defines where the filename is passed. For example, setting the 'open' item for a .jpg file to

    "C:\MyProgram\MyJPGViewer.exe /p /s" "%1"

    results in MyJPGViewer.exe receiving argv[1] as '/p', argv[2] as '/s', and argv[3] as the filename, quoted so it can contain embedded spaces.




  • True in theory. But then there is this handy feature that allows technical unskilled people to create file associations via dialog. And I think that dialog always sets the command string to "<program>" %1. Same happens if you drag a file onto an executable in Explorer. So unless you explicitly set your associations by yourself in a setup, you should always assume that people will call your program that way.



  • On the topic of command line options, another question: Even in the era
    of fancy GUI applications, many Windows programs still seem to support
    command line switches in addition to their GUI. (Like Explorer for
    example). What they don't support anymore is the conventional /?
    option. So is there maybe a newer "conventional way" to get info about
    the command line switches of such programs?



  • @PSWorx said:

    True in theory. But then there is this handy feature that allows technical unskilled people to create file associations via dialog. And I think that dialog always sets the command string to "<program>" %1. Same happens if you drag a file onto an executable in Explorer. So unless you explicitly set your associations by yourself in a setup, you should always assume that people will call your program that way.

    Ahhh... But I'm a firm believer in not assuming anything (you know the old saying, right?). The minute you assume, somehow all your assumptions become wrong, and you end up with all sorts of problems. Better, IMHO, to do things the right way in the first place. 



  • @PSWorx said:

    On the topic of command line options, another question: Even in the era of fancy GUI applications, many Windows programs still seem to support command line switches in addition to their GUI. (Like Explorer for example). What they don't support anymore is the conventional /? option. So is there maybe a newer "conventional way" to get info about the command line switches of such programs?

    Unless it's spelled out in the documentation, no. (Unless you count the hex viewer method of scanning the application. <g>) 



  • @KenW said:

    @PSWorx said:
    On the topic of command line options, another question: Even in the era
    of fancy GUI applications, many Windows programs still seem to support
    command line switches in addition to their GUI. (Like Explorer for
    example). What they don't support anymore is the conventional /?
    option. So is there maybe a newer "conventional way" to get info about
    the command line switches of such programs?
    Unless it's spelled out in the documentation, no. (Unless you count the hex viewer method of scanning the application. <g>) 

    I'm certain that if you ask MS support enough they will eventually tell you, or block your calls/emails/IP, really it just depends how persistent/annoying/stubborn you are.



  • I'm surprised nobody has mentioned this yet but your code isn't exception safe. You seem to be using legacy (non-standardised C++) instructions to manage files (FILE, i guess fopen/fclose, etc). Instead, unless you need ultra-low-level access, use file streams. These are exception safe. If you need to use low-level access, consider embedding the file access inside manager classes that automatically release allocated resources when destroyed.



  • File.. streams..? None of the books I read covered anything like that :/ I haven't even heard that term before. Is there a specific command you can give me that deals with input/output utilizing file streams, so I have something that I can research?



  • std::ifstream and std::ofstream from fstream.h. Personally I avoid them, fopen and friends offer the fprintf and fscanf functions whereas the fstream library requires the use of the overloaded bit-shift operators which is somewhat unfriendly. Also note that they behave like std::cout and std::cin. If you prefer cout and cin use the fstreams.


  • Discourse touched me in a no-no place

    @Lingerance said:

    std::ifstream and std::ofstream from fstream.h. Personally I avoid them, fopen and friends offer the f*printf and f*scanf functions whereas the fstream library requires the use of the overloaded bit-shift operators which is somewhat unfriendly. Also note that they behave like std::cout and std::cin. If you prefer cout and cin use the fstreams.
    You're comparing C with C++.

    If you're writing C++ use streams, if you're using C, use stdio. 

    And the Standard C++ headers don't have .h on the end. They never have.



  • @PJH said:

    You're comparing C with C++.

    How so? I can see how using cstdio is comparing C to C++; I prefer using *printf and *scanf because I can remember the formatting code a bit easier also you can #define your formats in a header in the situation where you need to modify alot of them at once without jumping through code. They also provide a nice visual reminder of what type of value you are expecting. There isn't any disadvantage to using them (aside from speed, but I doubt that the io class is significantly faster).
    @PJH said:
    And the Standard C++ headers don't have .h on the end. They never have.

    I was aware thank-you, I mentioned the extension to be clear about dealing with a header. Although I wouldn't say never, iirc some old versions of BC++ didn't like it when headers didn't have their extension I can't confirm atm because I can't find my 3.0 manual.



  • @Lingerance said:

    I prefer using *printf and *scanf because ... There isn't any disadvantage to using them .


    Yes, there is. Unless you've encapsulated their use inside manager classes, and written a correctly deallocating constructor, your code isn't exception safe when using fopen/flose etc (I'm not certain try/catch will handle all fail conditions that class deconstruction does). It is like using naked pointers isn't exception safe, using low-level resource-acquiring calls may cause your program to leak resources (memory, OS file handles, whathaveyou).



  • @Mikademus said:

    @Lingerance said:
    I prefer using *printf and *scanf because ... There isn't any disadvantage to using them .


    Yes, there is. Unless you've encapsulated their use inside manager classes, and written a correctly deallocating constructor, your code isn't exception safe when using fopen/flose etc (I'm not certain try/catch will handle all fail conditions that class deconstruction does). It is like using naked pointers isn't exception safe, using low-level resource-acquiring calls may cause your program to leak resources (memory, OS file handles, whathaveyou).

    Everyone learning C++ should read the C++ FQA lite from cover to cover.

    C++ FQA Lite


  • @arty said:

    @Mikademus said:

    @Lingerance said:
    I prefer using *printf and *scanf because ... There isn't any disadvantage to using them .


    Yes, there is. Unless you've encapsulated their use inside manager classes, and written a correctly deallocating constructor, your code isn't exception safe when using fopen/flose etc (I'm not certain try/catch will handle all fail conditions that class deconstruction does). It is like using naked pointers isn't exception safe, using low-level resource-acquiring calls may cause your program to leak resources (memory, OS file handles, whathaveyou).

    Everyone learning C++ should read the C++ FQA lite from cover to cover.

    C++ FQA Lite

    I take it you're criticising  that resources aren't deallocated automatically? Well, when using fopen etc you're using C, not C++. If you program C++, statically allocated objects will be managed for you and deallocated by the objects' destructors when going out of scope. This is more efficient, depending on your needs, than automatic collection. So you're not complaining about C++ here, you're actually talking about C.



  • @Mikademus said:

    @arty said:

    @Mikademus said:

    @Lingerance said:
    I prefer using *printf and *scanf because ... There isn't any disadvantage to using them .


    Yes, there is. Unless you've encapsulated their use inside manager classes, and written a correctly deallocating constructor, your code isn't exception safe when using fopen/flose etc (I'm not certain try/catch will handle all fail conditions that class deconstruction does). It is like using naked pointers isn't exception safe, using low-level resource-acquiring calls may cause your program to leak resources (memory, OS file handles, whathaveyou).

    Everyone learning C++ should read the C++ FQA lite from cover to cover.

    C++ FQA Lite

    I take it you're criticising  that resources aren't deallocated automatically? Well, when using fopen etc you're using C, not C++. If you program C++, statically allocated objects will be managed for you and deallocated by the objects' destructors when going out of scope. This is more efficient, depending on your needs, than automatic collection. So you're not complaining about C++ here, you're actually talking about C.

    BS. You're actually using the C library functions for IO _in_ C++. C++ code will happily use the C library. As for your previous argument to the C IO functions causing havoc when exceptions are thrown I'm sure the fact that an exception has been thrown is a sign that the program should be tearing down anyways. I can't for the like of me figure out how you can have an exception being thrown in a manner that will cause you to lose track of your pointer without the code doing some really stupid things (Like having the pointer in the try block's scope).


  • @Lingerance said:

    You're actually using the C library functions for IO _in_ C++. C++ code will happily use the C library.

    Yes, what is your point? I'm not saying that the C++ libraries (or your code for that matter) are not free to use the  C libraries. When they do they (hopefully) do so in a exception-safe way.



  • @Mikademus said:

    @Lingerance said:
    You're actually using the C library functions for IO in C++. C++ code will happily use the C library.

    Yes, what is your point? I'm not saying that the C++ libraries (or your code for that matter) are not free to use the  C libraries. When they do they (hopefully) do so in a exception-safe way.


    @Mikademus said:
    Well, when using fopen etc you're using C, not C++.




    Generally you should be handling the exception immediately other-wise you have to figure out where the exception is caught or not. Also if an exception is thrown you probably have worse problems to worry about.


    As for the argument about cstdio vs iostream I still hold my stance, cstdio is alot more comfortable and doesn't have that annoying << << << <<  fun



  • @arty said:

    Everyone learning C++ should read the C++ FQA lite from cover to cover. C++ FQA Lite

     

    i dont like this.  his defective c++ section is annoying.  its as if some java fanboy is complaining about c++ being too hard. 



  • @segmentation fault said:

    @arty said:

    Everyone learning C++ should read the C++ FQA lite from cover to cover.
    C++ FQA Lite

     

    i dont like this.  his defective c++ section is annoying.  its as if some java fanboy is complaining about c++ being too hard.

    Agreed.  I was ready to close the window when I read the part about how C++ was flawed because it'll let you access the 7th item in a 5-item array.  But it's a good thing I didn't, because then I would've missed how it's flawed because it has operator overloading, which simply made me pity the author.  And then there's this brilliant quote: "f you need an array in C++, you can use a C-like T arr[] or a C++ std::vector<T> or any of the array classes written
    before std::vector appeared in the C++ standard."  Multiple solutions to a problem = flaw.



  • @segmentation fault said:

    @arty said:

    Everyone learning C++ should read the C++ FQA lite from cover to cover.
    C++ FQA Lite

     

    i dont like this.  his defective c++ section is annoying.  its as if some java fanboy is complaining about c++ being too hard. 

    I laughed at the part about C++ having a "very complicated" type system. He has never seen a complicated type system. It's not "very complicated" unless, under the Curry-Howard equivalence, your type system is Turing-complete in its own right (which actually means that the typing relation is undecidable - you cannot write a program that will be able to identify whether any given input is correctly typed or not).

    Yes, they exist. 



  • @bstorer said:

      And then there's this brilliant quote: "f you need an array in C++, you can use a C-like T arr[] or a C++ std::vector<T> or any of the array classes written
    before std::vector appeared in the C++ standard."  Multiple solutions to a problem = flaw.

    Having multiple solutions to a problem is generally undesirable, because most likely every programmer (or team) will pick one and use it for all instances of the problem, thus forgetting that the other solution even exists. Then he quits and another programmer, who is supposed to know the language, has to maintain of the program. Unfortunately, the other programmer is used to the other solution to the problem, so a) he has problems to understand the program and b) he uses his favourite solution for all new ports, so the program becomes an inconsistent mix of solution A and solution B.

    Of course it's not a problem if there is only a handful of problems with multiple solutions in a language, but in C++, there are at least two solutions for every possilbe problem - the C solution and the C++ solution. And possibly there is a C++ solution with templates and one without. This is likely to lead to problems in the long term

    The array+vector example is obviously a bad choice, since most other languages (i.e. Java, C#) face the same "problem".



  • @ammoQ said:

    @bstorer said:

      And then there's this brilliant quote: "f you need an array in C++, you can use a C-like T arr[] or a C++ std::vector<T> or any of the array classes written
    before std::vector appeared in the C++ standard."  Multiple solutions to a problem = flaw.

    Having multiple solutions to a problem is generally undesirable, because most likely every programmer (or team) will pick one and use it for all instances of the problem, thus forgetting that the other solution even exists. Then he quits and another programmer, who is supposed to know the language, has to maintain of the program. Unfortunately, the other programmer is used to the other solution to the problem, so a) he has problems to understand the program and b) he uses his favourite solution for all new ports, so the program becomes an inconsistent mix of solution A and solution B.

    Of course it's not a problem if there is only a handful of problems with multiple solutions in a language, but in C++, there are at least two solutions for every possilbe problem - the C solution and the C++ solution. And possibly there is a C++ solution with templates and one without. This is likely to lead to problems in the long term

    The array+vector example is obviously a bad choice, since most other languages (i.e. Java, C#) face the same "problem".

    All languages have multiple solutions to a given problem.  The dilemma is that the "correct" solution varies from language to language, and even programmer to programmer.



  • @ammoQ said:

    @bstorer said:

      And then there's this brilliant quote: "f you need an array in C++, you can use a C-like T arr[] or a C++ std::vector<T> or any of the array classes written
    before std::vector appeared in the C++ standard."  Multiple solutions to a problem = flaw.

    Having multiple solutions to a problem is generally undesirable, because most likely every programmer (or team) will pick one and use it for all instances of the problem, thus forgetting that the other solution even exists.

    In the choice is between paradigm agnosticism and expressive consistency C++ chose the avenue that allows it to address the most problems. Though this may lead to competition of styles, the alternative --not being able to naturally or efficiently encompass a particular problem-- is worse.



  • @ammoQ said:

    Having multiple solutions to a problem is generally undesirable, because most likely every programmer (or team) will pick one and use it for all instances of the problem, thus forgetting that the other solution even exists.

    we call those bad developers who like to copy and paste.  if the problem is the developers, don't blame the language.



  • @segmentation fault said:

    @ammoQ said:

    Having multiple solutions to a problem is generally undesirable, because most likely every programmer (or team) will pick one and use it for all instances of the problem, thus forgetting that the other solution even exists.

    we call those bad developers who like to copy and paste.  if the problem is the developers, don't blame the language.

    If none of the available solutions has significant advantages over the other, at least in some situations, it would be rather stupid to mix them just because.

    BTW, copy-paste is still by far better than "exploring as many different approaches to the same problem as possible within the same project".



  • @asuffield said:

    I laughed at the part about C++ having a "very complicated" type system. He has never seen a complicated type system. It's not "very complicated" unless, under the Curry-Howard equivalence, your type system is Turing-complete in its own right (which actually means that the typing relation is undecidable - you cannot write a program that will be able to identify whether any given input is correctly typed or not). Yes, they exist. 

    You seem to be under the impression that C++ is not among them. (pdf link)



  • @Random832 said:

    @asuffield said:

    I laughed at the part about C++ having a "very complicated" type system. He has never seen a complicated type system. It's not "very complicated" unless, under the Curry-Howard equivalence, your type system is Turing-complete in its own right (which actually means that the typing relation is undecidable - you cannot write a program that will be able to identify whether any given input is correctly typed or not). Yes, they exist. 

    You seem to be under the impression that C++ is not among them. (pdf link)

    That trick relies on implementation-defined behaviour - specifically, infinite recursion in template expansion, which most C++ implementations don't permit because it would make it impossible to reliably type-check C++ programs; it's not a Turing machine if there is a fixed limit on the length of the tape, it's a linear bounded automaton, which corresponds to the context sensitive grammars ('type 1' in the Chomsky hierarchy, the one which nobody ever uses).

    Also, it's strictly an abuse of templates, rather than the type system itself - similar, but not quite the same thing. The Curry-Howard equivalence form looks a bit different (rather than assembling a Turing machine in a metaprogram, you assemble the lambda calculus in the typing and subtyping relations).



  • @ammoQ said:

    If none of the available solutions has significant advantages over the other, at least in some situations, it would be rather stupid to mix them just because.

    BTW, copy-paste is still by far better than "exploring as many different approaches to the same problem as possible within the same project".

    remind me as to why are you copy and pasting as a solution to the same problem instead of reusing the code by creating a common library?



  • @segmentation fault said:

    @ammoQ said:

    If none of the available solutions has significant advantages over the other, at least in some situations, it would be rather stupid to mix them just because.

    BTW, copy-paste is still by far better than "exploring as many different approaches to the same problem as possible within the same project".

    remind me as to why are you copy and pasting as a solution to the same problem instead of reusing the code by creating a common library?

    Of course one should create a reusable software module, e.g. a library, whenever that is reasonably possible.



  • @asuffield said:

    That trick relies on implementation-defined behaviour - specifically, infinite recursion

    Well, all real systems have limits - i suppose you're going to say that C++ _itself_ isn't turing-complete because you can run out of memory / stack space / time



  • @Random832 said:

    @asuffield said:

    That trick relies on implementation-defined behaviour - specifically, infinite recursion

    Well, all real systems have limits - i suppose you're going to say that C++ _itself_ isn't turing-complete because you can run out of memory / stack space / time

    C++ is Turing-complete because the language doesn't place any limits on memory usage, although a given host computer is not going to be a true Turing machine. However, a host is considered a sufficient approximation so long as sufficient memory is available, in particular when arbitrary amounts of swap space can be supplied on demand.

    The C++ template system does not normally have enough depth to be a sufficient approximation to anything remotely interesting. Analogy: would you consider a programming language to be Turing-complete if you were only allowed to write programs that compiled to a maximum of 16 machine-code instructions? Note that most programs cannot be represented by any sequence of 16 instructions, and none of the ones that can are Turing-machine simulators, so none of the usual interesting properties of a Turing machine (like the ability to emulate itself) will apply.



  • @ammoQ said:

    Of course one should create a reusable software module, e.g. a library, whenever that is reasonably possible.

     

    Well what I am saying is that if youre trying to solve the same problem, reuse the code.  If you cant, its a different problem. 



  • @segmentation fault said:

    @ammoQ said:

    Of course one should create a reusable software module, e.g. a library, whenever that is reasonably possible.

     

    Well what I am saying is that if youre trying to solve the same problem, reuse the code.  If you cant, its a different problem. 

    I'll try to explain my point of view with an example of bad code:

    void inconsistent(void) {
        int i;

        /* Part 1 */
        for (i=1; i<=10; i++) {
           doSomething(i);
        }

        /* Part 2 */
        i=0;
        while(11> ++i) {
           doSomethingElse(i);
        }

        /* Part 3 */
        i -= i;
        do {
           doYetanotherThing(++i);
        } while (i<10);
    }

     
    Those three parts do basically the same - a loop from 1..10 - but in three different styles, so it would not be easy to recognize if it wasn't an obviously artifical example in a WTF thread.

     

     



  • not be easy to recognize what?  im sorry im not quite sure what you wanted to say.
     



  • @ammoQ said:

    @segmentation fault said:

    @ammoQ said:

    Of course one should create a reusable software module, e.g. a library, whenever that is reasonably possible.

     

    Well what I am saying is that if youre trying to solve the same problem, reuse the code.  If you cant, its a different problem. 

    I'll try to explain my point of view with an example of bad code:

    void inconsistent(void) {
        int i;

        /* Part 1 */
        for (i=1; i<=10; i++) {
           doSomething(i);
        }

        /* Part 2 */
        i=0;
        while(11> ++i) {
           doSomethingElse(i);
        }

        /* Part 3 */
        i -= i;
        do {
           doYetanotherThing(++i);
        } while (i<10);
    }

     
    Those three parts do basically the same - a loop from 1..10 - but in three different styles, so it would not be easy to recognize if it wasn't an obviously artifical example in a WTF thread.

    When coding in narrative form, switching between these various styles can make the text flow more smoothly. Hence, you always want a language to let you mix them. 



  • @segmentation fault said:

    not be easy to recognize what?  im sorry im not quite sure what you wanted to say.

    Recognize that the three loops are effectively "for" loops from 1 .. 10.



  • @asuffield said:

    When coding in narrative form, switching between these various styles can make the text flow more smoothly. Hence, you always want a language to let you mix them. 

    True, but you wouldn't want to write narrative code in a language with C-like syntax anyway. Cobol is much better suited for the job. Though Cobol programs probably tell sad stories...


     



  • @ammoQ said:

    @asuffield said:

    When coding in narrative form, switching between these various styles can make the text flow more smoothly. Hence, you always want a language to let you mix them. 

    True, but you wouldn't want to write narrative code in a language with C-like syntax anyway.

    I've always found it fairly easy... my non-trivial C code tends to look like one long comment with bits of code scattered through it. 



  • @ammoQ said:

    Recognize that the three loops are effectively "for" loops from 1 .. 10.

     

    for, while, and do while are 3 different kinds of loops that should be used in 3 different kinds of scenarios. 


Log in to reply