How Optind Variable Gets Assigned in C

Jinku Hu Nov 28, 2023
  1. Use the getopt Function to Parse Command-Line Options in C
  2. Use optind and optarg Variables to Process argv Elements in C
  3. Use the getopt_long Function to Parse Command-Line Options in C
  4. Conclusion
How Optind Variable Gets Assigned in C

In C programming, the optind variable is often used in conjunction with command-line argument parsing libraries like getopt or getopt_long. It keeps track of the index of the next argument to be processed.

optind can be assigned in several ways depending on the method used for parsing command-line arguments. This article will demonstrate multiple methods about how the optind variable gets assigned in C.

Use the getopt Function to Parse Command-Line Options in C

Typical command-line programs on UNIX-based systems take arguments and options. Options are usually specified with characters that follow hyphens, and each unique character either indicates information about the given argument or yields the specific behavior of the program to be executed.

Options can have mandatory or optional arguments; in the latter case, it’s common for programs to allow grouping of the options after a single hyphen, and the only argument may be passed at the end of the command.

The getopt function is used to parse the options, retrieve given arguments from the program, and execute the corresponding code paths based on the input. getopt takes three arguments, the first two of which are argc and argv passed to the main function.

The third argument is optstring - a pointer to a character string representing the legitimate option characters. getopt needs to be called successively until every option is retrieved.

Syntax:

#include <unistd.h>

int getopt(int argc, char *const argv[], const char *optstring);
  • argc: Number of arguments passed to the program.
  • argv: Array of strings containing the arguments.
  • optstring: String containing the expected options. Each character represents a single-letter option. If a character in optstring is followed by a colon (:), it indicates that the option requires an argument.

The function returns:

  • -1 when there are no more options to process.
  • The character code of the next option found in the command line.
  • If an option requires an argument, optarg (externally defined) will contain a pointer to the option’s argument.

Additionally, the external variable optind is used to track the index of the next argument to be processed; that is not an option.

In the following example, we demonstrate a program that takes options with p and x characters. Note that optstring starts with the colon, which indicates the value that needs to be returned by the getopt call when the missing arguments are encountered.

Also, a colon specified after a character (e.g., p) indicates that the argument is required for the option; two colons mean the argument is optional. The same option character can be passed multiple times on the command line.

The getopt function returns the option character if successful or returns the character ? if the encountered option character is not in optstring.

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

int main(int argc, char *argv[]) {
  int opt, xnum = 0;
  char *pstr = NULL;

  while ((opt = getopt(argc, argv, ":p:x")) != -1) {
    printf("opt = %3d (%c); optind = %d\n", opt, opt, optind);

    switch (opt) {
      case 'p':
        pstr = optarg;
        break;
      case 'x':
        xnum++;
        break;
      case ':':
        fprintf(stderr,
                "Missing argument!\n"
                "Usage: %s [-p arg] [-x]\n",
                argv[0]);
        exit(EXIT_FAILURE);
      case '?':
        fprintf(stderr,
                "Unrecognized option!\n"
                "Usage: %s [-p arg] [-x]\n",
                argv[0]);
        exit(EXIT_FAILURE);
      default:
        fprintf(stderr, "Unexpected case in switch()");
        exit(EXIT_FAILURE);
    }
  }

  exit(EXIT_SUCCESS);
}

Sample Command:

./program_name -p hello -p there

Output:

opt = 112 (p); optind = 3
opt = 112 (p); optind = 5

Use optind and optarg Variables to Process argv Elements in C

The previous code sample demonstrates the typical getopt usage, where the function is called from a while loop expression until it returns the error code -1. Meanwhile, the switch statement checks for possible getopt return values to execute the corresponding code blocks.

Note that the optind variable represents the next element’s index in the argv, and it’s initialized to 1 before the first call to getopt.

On the other hand, optarg is an external variable that points to the argument following the current option character. If the option does not include an argument, then optarg is set to zero.

  • optind: It is an external variable that tracks the index of the next argv element to be processed. Initially set to 1, optind is updated by getopt as options are parsed.
  • optarg: Also an external variable, it holds the argument (if any) associated with the current option. optarg is set by getopt when an option that expects an argument is encountered.

The primary use of optind and optarg revolves around parsing command-line options. This involves iterating through the command-line arguments using getopt in a loop until all options are processed.

The next code example shows how to save the argument pointed by the optarg variable and then operate on it as needed. Mind that the argument can follow the option without a space delimiter.

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

int main(int argc, char *argv[]) {
  int opt, xnum = 0;
  char *pstr = NULL;

  while ((opt = getopt(argc, argv, ":p:x")) != -1) {
    printf("opt = %3d (%c); optind = %d\n", opt, opt, optind);

    switch (opt) {
      case 'p':
        pstr = optarg;
        break;
      case 'x':
        xnum++;
        break;
      case ':':
        fprintf(stderr,
                "Missing argument!\n"
                "Usage: %s [-p arg] [-x]\n",
                argv[0]);
        exit(EXIT_FAILURE);
      case '?':
        fprintf(stderr,
                "Unrecognized option!\n"
                "Usage: %s [-p arg] [-x]\n",
                argv[0]);
        exit(EXIT_FAILURE);
      default:
        fprintf(stderr, "Unexpected case in switch()");
        exit(EXIT_FAILURE);
    }
  }

  if (xnum != 0) printf("-x was specified (count=%d)\n", xnum);
  if (pstr != NULL) printf("-p was specified with the value \"%s\"\n", pstr);
  if (optind < argc)
    printf("First non-option argument is \"%s\" at argv[%d]\n", argv[optind],
           optind);

  exit(EXIT_SUCCESS);
}

This code exemplifies a robust approach to parsing command-line options in C, utilizing getopt alongside optind and optarg to efficiently process arguments, handle options, and provide informative output regarding the specified options and their arguments.

Sample Command:

./program_name -p hello

Output:

opt = 112 (p); optind = 3
-p was specified with the value "hello"

Use the getopt_long Function to Parse Command-Line Options in C

The getopt_long function is part of the C standard library <getopt.h>. It facilitates the parsing of command-line options, allowing programs to handle both short and long options, providing a more descriptive and user-friendly interface.

Syntax:

#include <getopt.h>

int getopt_long(int argc, char *const argv[], const char *optstring,
                const struct option *longopts, int *longindex);
  • argc: Number of arguments passed to the program.
  • argv: Array of strings containing the arguments.
  • optstring: String containing the short options.
  • longopts: Array of struct option defining long options.
  • longindex: Pointer to an integer to store the index of the next long option found (can be NULL).

Using struct option

The struct option structure allows defining long-named options alongside their attributes:

struct option {
  const char *name;
  int has_arg;  // Indicates if the option requires an argument
  int *flag;  // If not NULL, points to a variable to set a value for the option
  int val;    // Value to return if the option is found
};
  • name: The long name of the option.
  • has_arg: Specifies whether the option requires an argument (values: no_argument, required_argument, or optional_argument).
  • flag: If not NULL, it sets a variable to a specified value when the option is found.
  • val: The value to return if the option is encountered.

Let’s delve into an example showcasing the usage of getopt_long to process command-line options:

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

int main(int argc, char *argv[]) {
  struct option long_options[] = {{"help", no_argument, NULL, 'h'},
                                  {"verbose", no_argument, NULL, 'v'},
                                  {"output", required_argument, NULL, 'o'},
                                  {0, 0, 0, 0}};

  int opt;
  int option_index = 0;

  while ((opt = getopt_long(argc, argv, "hvo:", long_options, &option_index)) !=
         -1) {
    switch (opt) {
      case 'h':
        // Process --help or -h option
        break;
      case 'v':
        // Process --verbose or -v option
        break;
      case 'o':
        // Process --output or -o option with argument
        printf("Option 'output' specified with value: %s\n", optarg);
        break;
      case '?':
        // Invalid option or missing argument
        fprintf(stderr, "Unrecognized option\n");
        exit(EXIT_FAILURE);
    }
  }

  // Process non-option arguments if any
  for (; optind < argc; optind++) {
    printf("Non-option argument: %s\n", argv[optind]);
  }

  return 0;
}

The output of the code depends on the arguments passed when executing the program. Let’s break down the code’s behavior:

  • It defines three long options: --help (-h), --verbose (-v), and --output (-o) with an expected argument.

  • Inside the while loop, it uses getopt_long to process command-line options until no options are left (opt becomes -1).

  • For each recognized option, the corresponding case block is executed:

    • 'h': Represents the help option.
    • 'v': Represents the verbose option.
    • 'o': Represents the output option, and it prints the provided argument using optarg.
    • '?': Indicates an unrecognized option or a missing argument, triggering an error message and program termination with failure status.

After parsing options, the code iterates through any remaining non-option arguments using optind and prints them.

To simulate the output, consider executing the program with different arguments:

./program_name -o output_value --verbose argument1 argument2

The output would display:

Option 'output' specified with value: output_value
Non-option argument: argument1
Non-option argument: argument2

This output illustrates the processing of the --output (-o) option with the provided value, followed by the printing of non-option arguments (argument1 and argument2) encountered after parsing options.

Sample Command:

./program_name -o hello

Output:

Option 'output' specified with value: hello

Key Points:

  • Structuring Long Options: struct option is used to define long-named options with their respective attributes.
  • Looping Through Options: The while loop utilizes getopt_long to parse command-line options, including both short and long options.
  • Switch Statement Handling Options: The switch statement processes each recognized option according to its corresponding case.
  • Error Handling: It handles cases of unrecognized options or missing arguments.
  • Accessing Non-Option Arguments: optind is used to access non-option arguments after option parsing.

Conclusion

In summary, understanding the intricacies of command-line argument parsing in C involves using variables like optind in conjunction with libraries such as getopt or getopt_long. These variables aid in tracking the index of the next argument to be processed in command-line argument parsing.

The getopt function is commonly used to handle short options in C programs. It processes options characterized by single letters, allowing for arguments to be passed alongside specific options.

Utilizing optind and optarg variables with getopt helps navigate through command-line arguments efficiently, indicating the next argument to be processed and pointing to the argument associated with the current option.

Additionally, getopt_long offers a more versatile approach by supporting both short and long options, enhancing readability and user-friendliness. Using a struct option, it defines long-named options alongside their attributes and allows comprehensive parsing of command-line options, enabling error handling and accessing non-option arguments with ease.

Both getopt and getopt_long facilitate the efficient handling of command-line interfaces in C, allowing developers to create robust and user-friendly programs by providing mechanisms to parse options, process arguments, and manage non-option elements effectively. These tools, in combination with optind and optarg, empower programmers to develop flexible and feature-rich command-line applications in C.

Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook