I noticed during debugging that the optarg variable of GNU's getopt remained zero (i.e. address 0x0) during debugging. But when optarg is used as right-hand operand of assignment or passed as argument to a parameter, the expected value is applied. The example from GNU:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c': # b 26
cvalue = optarg; # gdb stops right before executing this line
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Usage
$ gcc -o getopt getopt.c -g # debugging ON, optimizations OFF
$ gdb getopt
(gdb) b 26 # set breakpoint
(gdb) r -cfoo
(gdb) p optarg
$1 = 0x0 # no "foo"?
(gdb) n # executes cvalue = optarg
(gdb) p cvalue
$2 = 0x7fffffffea99 "foo" # here it is, please don't expect to get the same memory-address
Why optarg doesn't contain the character string "foo" at line 26? What do I miss here?
More bewildering, I figured out it doesn't contain "foo" even after the line has been executed. I've put a glance at the original source and didn't notice something like a compiler optimization. I'm using GCC 11.1.0 on Archlinux, x86_64.
Thank you
PaulMcKenzie seems right. It is probably this old bug 8588 within GDB. GDB struggles handling the GOT (Global-Offset-Table) right which is a part of PIC (Position-Independent-Code].
Workaround
p (char*)'optarg#GLIBC_2.2.5'
We reference here the variable optarg and the version symbol of the GLIBC. The version 2.2.5 is the baseline which already includes provides GNU getopt and therefore the newer ones don't apply.
Thank you
Related
This is my first post on this site so please forgive any formatting errors.
I am coding a small program to get simple information from a file like amount of words, sorting it etc. However I started simply by using getopt since I want to use the command line to parse my commands. This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
int value = 0;
int main(int argc, char **argv) {
extern char *optarg;
extern int optind;
int c, err = 0;
int cflag = 0, sflag = 0, fflag = 0;
char *substring;
// usage from instructions in case of error
static char usage[] = "usage: mywords [-cs] [-f substring] filename";
// only f flag requires additional input
while ((c = getopt(argc, argv, "csf:")) != -1)
switch (c) {
case 'c':
cflag = 1;
break;
case 's':
sflag = 1;
break;
case 'f':
fflag = 1;
printf("Before assigning to substring\n");
substring = optarg;
printf("After\n");
break;
case '?':
err = 1;
break;
}
if (fflag = 1) {
printf("%c ", &substring);
}
}
I will then input something like this to the command line after I run my makefile (which runs successfully with no errors):
mywords -f test
and ideally the output would be
test
The printf statements I have in the fflag are simple test prints to see if I was even reaching there. Thank you for your help in advance.
EDIT
It was fixed. David Collins had the right answer. Thank you so much everyone
I have noticed three issues in you code. (There may be other small issues but addressing the following should get you up and running I think.)
Testing for equality
You should use if (fflag == 1) instead of if (fflag = 1).
Pointer de-referencing
If you want to retrieve the value of the character pointed to by substring, you would use *substring instead of &substring.
But you probably don't want to do this. See below.
printf() format specifiers
When printing a string / character array, use the %s specifier instead of %c. (%c is for single characters). So you should have
if (fflag == 1) {
printf("%s ", substring);
}
Or - more simply - just
if (fflag) {
puts(substring)
}
since any non-zero value evaluates to true in C (and you initialize fflag to zero at the start of your program).
I am working on trying to take in command line arguments. If I want to have multiple optional command line arguments how would I go about doing that? For example you can run the program in the following ways:
(a is required every instance but -b -c -d can be given optionally and in any order)
./myprogram -a
./myprogram -a -c -d
./myprogram -a -d -b
I know that getopt()'s third argument is options. I can set these options to be "abc" but will the way I have my switch case set up causes the loop to break at each option.
The order doesn't matter so far as getopt() is concerned. All that matters is your third argument to getopt() (ie: it's format string) is correct:
The follow format strings are all equivalent:
"c:ba"
"c:ab"
"ac:b"
"abc:"
In your particular case, the format string just needs to be something like "abcd", and the switch() statement is properly populated.
The following minimal example¹ will help.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
{
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
¹Example taken from the GNU manual
I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).
I wrote (copied and pasted from Google and simplified) a C program to use getopt to print out the values of the arguments passed in from the Unix command line.
From Unix command line:
./myprog -a 0 -b 1 -c 2
My C code is:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i;
while ((i = getopt(argc, argv, "abc")) != -1) {
switch (i) {
case 'a':
printf("A = %s\n", optarg);
break;
case 'b':
printf("B = %s\n", optarg);
break;
case 'c':
printf("C = %s\n", optarg);
break;
default:
break;
}
}
return 0;
}
I want to program to print out each of the values passed e.g.
A = 0
B = 1
C = 2
However it is not printing out anything at all.
You forget about ":" after any option with argument. If you will change one line
while ((i = getopt(argc, argv, "a:b:c:")) != -1) {
you will get working variant.
Read properly man 3 getopt, it said about third argument of getopt that
… optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so
getopt() places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option
takes an optional arg; if there is text in the current argv-element (i.e., in the same word as the option name itself, for example, "-oarg"), then it is
returned in optarg, otherwise optarg is set to zero. …
Hello I'm new with C and I'm trying to start this lab where the command syntax is to first list any command line flags then list one or more file names.
I'm having trouble organizing how I want to scan the input arguments and differentiating them between flags and file names.
I thought of doing a loop to see if the argument is a flag or file name. But I'm unsure how to begin implementing it. Since the first 4 arguments can be potential flags in any order then anything after is the file name. But it is also possible for no flags to be given and just start with filenames. I don't know at all how to initalize this loop to go through each argument 1 by 1. Can anyone help please?
Example of possible command line arguments:
wc fcopy.c head.c (no flags given just file names)
wc -l -c -w -L fcopy.c head.c a.exe (flags given and multiple files)
wc -l -w -c -L fcopy.c (flags given and 1 file name)
Reading command line args one by one is pretty simple:
int main( int argc, // Number of strings in array argv char *argv[])
The two basic args to a C function are argc (int number of args), and argv (an array of strings for the args)
The first string is always the name of the program that is running, after that is the args that were passed over the command line.
if(argc > 1)
for( count = 1 count < argc; count++ )
printf("%s", argv[count]);
Will display to the screen each of the arguments passed in past the name of the calling program.
I assume your flags are passed with a "-" as the first character? If so, you can check the contents of the first character in each string for a '-' to tell if its a flag or not.
You can use getopt()
Check these questions:
Parsing command-line arguments?
Handling command line options before and after an argument in C
Argument-parsing helpers for C/UNIX
Getopt shift optarg
Check out getopt, it allows you to parse command line arguments and their flags:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ( (c = getopt (argc, argv, "abc:")) != -1 )
switch (c) {
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Example of Parsing Arguments with getopt
Also see http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html