views:

125

answers:

6

I am reading chapter 2 of Advanced Linux Programming:
http://www.advancedlinuxprogramming.com/alp-folder/alp-ch02-writing-good-gnu-linux-software.pdf

In the section 2.1.3 Using getopt_long, there is an example program that goes a bit like this:

int main (int argc, char* argv[]) {
  int next_option;
  // ...
  do {
    next_option = getopt_long (argc, argv, short_options, long_options, NULL);
    switch (next_option) {
       case ‘h’: /* -h or --help */
       // ...
    }
    // ...

The bit that caught my attention is that next_option is declared as an int. The function getopt_long() apparently returns an int representing the short command line argument which is used in the following switch statement. How come that integer can be compared to a character in the switch statement?

Is there an implicit conversion from a char (a single character?) to an int? How is the code above valid? (see full code in linked pdf)

+4  A: 

You are mistaken -- getopt_long(3) returns an int.

Shaggy Frog
So how come this int can be compared to 'h' or other characters in the switch statement?
augustin
Thanks for the notice but it does not answer my question. I have edited the question accordingly.
augustin
a char is nothing particularly special, just a 1-byte integer-type variable. If you compare a char to an int, it's as if you're comparing two ints (same as int to long or long long).
jkerian
@jkerian Thanks. You answer more or less what I was really trying to ask. I didn't know you could do that.
augustin
A: 

As the other answerer says, you're asking the wrong question here. But to answer the question you did ask:

No implicit casting from char* to an int is available. On x86 machines, both int and char* are 32 bits long, so it's "safe" to explicitly cast:

int x = (int*) &someChar;

BUT HIGHLY NOT RECOMMENDED!!!

On x64 machines, this will not work! int remains 32 bits long, but all pointers are now 64 bits long... so you'll lose data in the process!

Computer Guru
So, what do you make of the sample code in chapter 2 of "Advanced Linux Programming"? How should the code be re-factored to be safe on my 64 bit CPU/OS?
augustin
+1  A: 

Several functions return int in C, but char in C++. Returning an int when a char would make more sense is simply an old C cultural decision. Plus, in a few cases, it's necessary so that a function can return sentinels like EOF.

Max Lybbert
+4  A: 

Neither C nor C++ have a type that can store "characters" as values with some dedicated character-specific properties. In that sense, there's no "character" type neither in C nor in C++.

In both C++ and C languages char is an integral type. It contains numbers. It is just a smallest (in terms of range) integral type. Conversion between char and int exists, just like it exists between int and long or int and short. char has no special status among other integral types (aside from the fact that char type it is distinct from signed char type).

A literal of the form 'h' in C++ has type char, but as any other integral type it is comparable to int. That's why you can use it in case label the way it is used in your original example.

In other words, your original code is as "strange" as

switch (next_option) {
       case 1L: ...
       // ...
    }

would be. In this case the switch argument is an int, but the case label is a long. The code is valid. Do you find it surprising? Probably not. Your example with 'h' is in not much different.

AndreyT
@AndreyT: I really wish the tag "newbie" were accepted here. Yes, I do find things like this surprising. I didn't expect it. You provided some pointers to concepts I could search and study more. I'll need time for this to sink in. Thanks.
augustin
"char has no special status among other integral types" It has no trap values! :)
GMan
@GMan i regard that as a little useful property, though :( You can still not reliable use it to copy over arbitrary bytes, because only for *unsigned char*, it's guaranteed that the copied bytes are exactly the same (for `char`, you may have multiple representations for the same value, for instance a "negative" and "positive" 0).
Johannes Schaub - litb
A: 

According to the man page, getopt_long returns an int. And yes, there is an implicit cast from char to int; a char is just a one-byte integer value.

So in this case, the cast is not happening when assigning to next_option, but in the case statement where you have a character constant being compared to an int. Of course, this is assuming you compile this as C++. In C++, a character constant is of type char, but in C it's of type int, so if you compile this code as C then there's no type conversion at all.

(And in your question you mention char*, but you probably meant char; there are no pointers being used here.)

mkarasek
A: 

Think of a char as a 8bit int. You can perform integer operations on chars and you can even declare them as unsigned. You wouldn't be surprised if you could compare a short and a long. Why should comparing a char and an int be different?

dan_waterworth
No, don't think of it as an 8 bit int. Think of it as the smallest integral type in C++, which may or may not be 8 bits and may or may not be signed or unsigned.
GMan
In C++ a byte must be at least 8 bits. A char must be a single byte.
dan_waterworth
@dan_water: A char is a single byte, and yes it must be at least 8 bits. You said think of it *as* 8 bits, a bad practice to get in to.
GMan