Thread: The significance of int casting in a programm with array of structures.

  1. #1
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357

    The significance of int casting in a programm with array of structures.

    I am doing an exercise which has to do with International country codes.The user must give a code and the programm will display the corresponding country.

    Code:
    #include <stdio.h>
    
    #define COUNTRY_COUNT \
      ((int) (sizeof(country_codes) / sizeof(country_codes[0])))
    
    struct dialing_code {
      char *country;
      int code;
    };
    
    const struct dialing_code country_codes[] =
      {{"Argentina",            54}, {"Bangladesh",      880},
       {"Brazil",               55}, {"Burma (Myanmar)",  95},
       {"China",                86}, {"Colombia",         57},
       {"Congo, Dem. Rep. of", 243}, {"Egypt",            20},
       {"Ethiopia",            251}, {"France",           33},
       {"Germany",              49}, {"India",            91},
       {"Indonesia",            62}, {"Iran",             98},
       {"Italy",                39}, {"Japan",            81},
       {"Mexico",               52}, {"Nigeria",         234},
       {"Pakistan",             92}, {"Philippines",      63},
       {"Poland",               48}, {"Russia",            7},
       {"South Africa",         27}, {"South Korea",      82},
       {"Spain",                34}, {"Sudan",           249},
       {"Thailand",             66}, {"Turkey",           90},
       {"Ukraine",             380}, {"United Kingdom",   44},
       {"United States",         1}, {"Vietnam",          84},
       {"Venezuela",            58}, {"Greece",           30},
       {"Ireland" ,            353}, };
    
    int main(void)
    {
      int code, i;
    
      printf("Enter dialing code: ");
      scanf("%d", &code);
    
      for (i = 0; i < COUNTRY_COUNT; i++)
        if (code == country_codes[i].code) {
          printf("The country with dialing code %d is %s\n",
                 code, country_codes[i].country);
          return 0;
        }
    
      printf("No corresponding country found\n");
     
      return 0;
    }
    This solution comes from : Answers to Selected Exercises in Chapter 16 of C Programming: A Modern Approach - Second Edition

    1. What is the significance of int cast? I mean i know what it does ... but I tried to put many countries and the result of sizeof(country_codes)/sizeof(country_codes[0]) was always an integer not a double or something that can make us to think about an int casting.

    2. Hence the macro is not parameterized the last pair of extra braces it comes due to int cast? and in my implementation I didn't put the array of structures as global. Here is my implementation of this exercise :

    Code:
    #include <stdio.h>
    #include <stdbool.h>
    #define LEN 33
    
    struct dialing_code {
    	char *country ; 
    	int code;
    } ;
    
    
    int main(void)
    {	
    	const struct dialing_code country_codes[LEN] = 
    	{  {"Argentina" ,           54}   ,    {"Bangladesh" ,         880}  , 
    	   {"Brasil" ,              55}   ,    {"Burma (Myanmar)" ,     95}  , 
    	   {"China" ,               86}   ,    {"Colombia" ,            57}  , 
    	   {"Congo" ,              243}  ,     {"Egypt" ,               20}  , 
    	   {"Egypt" ,               20}   ,    {"Ethiopia" ,           251}  , 
    	   {"France" ,              33}   ,    {"Germany" ,             49}  , 
    	   {"India" ,               91}   ,    {"Indonesia" ,           62}  ,
    	   {"Iran" ,                98}   ,    {"Italy" ,               39}  , 
    	   {"Japan" ,               81}   ,    {"Mexico" ,              52}  , 
    	   {"Nigeria" ,            234}   ,    {"Pakistan" ,            92}  ,
    	   {"Philippines" ,         63}   ,    {"Poland" ,              48}  , 
    	   {"Russia" ,               7}   ,    {"South Africa" ,        27}  , 
    	   {"South Korea" ,         82}   ,    {"Spain" ,               34}  , 
    	   {"Sudan" ,              249}   ,    {"Thailand" ,            66}  , 
    	   {"Turkey" ,              90}   ,    {"Ukraine" ,            380}  , 
    	   {"United Kingdom" ,      44}   ,    {"United States" ,       1 }  , 
    	   {"Vietnam" ,             84}  };
    	   
    	   int choice , i;
    	   bool sentinel = false;
    	   
    	   for(i=0; i<LEN; i++)
    			printf(" %s: %d \n" , country_codes[i].country , country_codes[i].code);
    	    
    	   for(;;) {
    			  putchar('\n');
    		      printf("Give the code (press 0 to terminate): ");
    	          scanf("%d" , &choice);
    	          
    	          if( !choice )
    	          return 0;
    		
    				for(i=0; i<LEN; i++){
    					if( choice == country_codes[i].code ){
    						printf("The country is: %s " , country_codes[i].country);
    						sentinel = true;
    						break;
    			        }
    			        
    			    sentinel = false; 
    			     
    		        }
    		        
    		        if( !sentinel )
    				printf(" There is no such a country\t");
    	}
    	
    	return 0;
    }
    Thank you in advance.
    Last edited by Mr.Lnx; 06-18-2013 at 07:56 AM.

  2. #2
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    I found it ... sizeof produces a value of size_t so the cast is mandatory if we want to be safe with the code and avoid the warnings.

    If someone has a better opinion or a comment for my second implementation of the exercise will be helpful. I am ok with the questions though. Thank you

  3. #3
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by Mr.Lnx View Post
    I found it ... sizeof produces a value of size_t so the cast is mandatory if we want to be safe with the code and avoid the warnings.
    You can use index of type size_t and avoid casting at all, as well as warnings
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  4. #4
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    You mean

    Code:
     size_t i;  /* i for loop iteration */
    Yes you can but I think it has more advantages ... to have a macro like the first implementation. The reason is simple : even if the length will be changed later (assuming that they are not all the countries here) you have no to change your macro definition instead of the case of LEN in the second implementation.

  5. #5
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Implicit conversions done when comparing integers of different types (or different signedness) follow C integer conversion rules. (See here for further info and examples.)

    Casting the unsigned type to a large enough signed type avoids any ambiguity.
    In your code, the cast also says that the number of country codes must always fit an int, which considering the usage is quite all right.

    On my 64-bit machine, I can easily dynamically allocate an array with more entries that will fit in an int, so it is a good idea to be aware of the limitations your code sets. In your code example, i is never negative, so you could change its type to size_t and drop the (int) cast from the macro (so that it also evaluates to an integer value of size_t type), to support the maximum possible number of structures in any array.

    Quote Originally Posted by Mr.Lnx View Post
    the last pair of extra [parentheses] [are needed for the] int cast?
    No. The outermost pair of parentheses are to make sure the expression is treated as a single value.

    Consider the following counterexample:
    Code:
    #include <stdio.h>
    
    #define SUM1(a, b) a + b
    #define SUM2(a, b) (a + b)
    #define SUM3(a, b) (int)(a + b)
    
    int main(void)
    {
        printf("4*SUM1(2,3) = %d\n", 4*SUM1(2,3));
        printf("4*SUM2(2,3) = %d\n", 4*SUM2(2,3));
        printf("4*SUM3(2,3) = %d\n", 4*SUM3(2,3));
        printf("sizeof(SUM1(2.0f, 3.0f)) = %d\n", (int)sizeof(SUM1(2.0f, 3.0f)));
        printf("sizeof(SUM2(2.0, 3.0)) = %d\n", (int)sizeof(SUM2(2.0, 3.0)));
        printf("sizeof(SUM3(2.0, 3.0)) = %d\n", (int)sizeof(SUM3(2.0, 3.0)));
        return 0;
    }
    On i386 and similar architectures, the above code yields
    Code:
    4*SUM1(2,3) = 11
    4*SUM2(2,3) = 20
    4*SUM3(2,3) = 20
    sizeof(SUM1(2.0f, 3.0f)) = 4
    sizeof(SUM2(2.0, 3.0)) = 8
    sizeof(SUM3(2.0, 3.0)) = 4
    4*SUM1(2,3) evaluates to 4*2+3, which is mathematically 8+3 = 11.
    4*SUM2(2,4) evaluates to 4*(2+3), which is mathematically 4*5 = 20.
    4*SUM3(2,4) evaluates to 4*(int)(2+3), which is mathematically 4*(2+3) = 20.

    When either operand is a floating-point number, SUM1 and SUM2 evaluate to a floating-point value, but SUM3 always evaluates to an int (applying appropriate casting rules).

    2.0f and 3.0f are floating-point values of float type, and sizeof (float) == 4.
    2.0 and 3.0 are floating-point values of double type, and sizeof (double) == 8.
    sizeof (int) is 4.

    Quote Originally Posted by Mr.Lnx View Post
    in my implementation I didn't put the array of structures as global.
    You don't have to, if you don't want to. However, if you want it to be a static constant (unmodifiable), you should tell the compiler so; it can often generate better code if you do.

    Personally, I find it much more reliable to have a sentinel value in the array, for example
    Code:
    static const struct {
        int code;
        char *country;
    } dialing_code[] = {
        {  54, "Argentina" },
        { 880, "Bangladesh" },
        /* ... */
        {  84, "Vietnam" },
        {   0, NULL }
    };
    The sentinel is the final entry, country code 0 (invalid) and/or NULL name. Usually, you want to use a sentinel value in a specific field -- say, a NULL instead of a valid string -- so that the sentinel is easy to check for.

    Consider the following loop that searches for the code corresponding to name, using the structure above:
    Code:
        char *name; /* Name we wish to find the code for */
        size_t i;
    
        for (i = 0; dialing_code[i].country != NULL; i++)
            if (!strcmp(name, dialing_code[i].country))
                break;
    
        /* If dialing_code[i].country != NULL,
         * then dialing_code[i].code is the code
         * corresponding to name.
         * Otherwise the code is unknown. */
    If the loop finds a match, it will break out, and i will be the index to the matching entry. Otherwise, i will be the index of the sentinel entry after the loop.

  6. #6
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    you can still have the macro if your 'i' is size_t. you just would not need the cast in the macro.

  7. #7
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    @Nominal Animal I think 4*(int)(2+3) would be the same with 4 * ( (int)(2+3) )

    that is why I was wondering if the outermost extra braces are mandatory .. I think

    (int) ( sizeof(a) / sizeof(a[0]) ) is same with ( (int) ( sizeof(a) / sizeof( a[0])) ) the second is more readable than the first I am right?

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    (int) ( sizeof(a) / sizeof(a[0]) ) is same with ( (int) ( sizeof(a) / sizeof( a[0])) ) the second is more readable than the first I am right?
    I consider the former to be more readable than the latter since the extra parentheses clarify nothing.

    The thing is, when defining a macro, those parenthese are usually not extra: they ensure that when the macro is used as a sub-expression, its meaning will not be changed due to some adjacent sub-expression having higher precedence. This risk is fairly low here because cast operators have rather high precedence, but it better to be safe than sorry that you got careless.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Quote Originally Posted by laserlight View Post
    I consider the former to be more readable than the latter since the extra parentheses clarify nothing.

    The thing is, when defining a macro, those parenthese are usually not extra: they ensure that when the macro is used as a sub-expression, its meaning will not be changed due to some adjacent sub-expression having higher precedence. This risk is fairly low here because cast operators have rather high precedence, but it better to be safe than sorry that you got careless.
    Yes I agree of course that is the basic meaning you are absolutely good , but here if we ommit the 2 as I wrote before the result will not be changed.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    Yes I agree of course that is the basic meaning you are absolutely good , but here if we ommit the 2 as I wrote before the result will not be changed.
    And your point is?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    Quote Originally Posted by laserlight View Post
    And your point is?
    For me so far the two last braces are not required but I am thinking why the first implementation prefers it. That is why I wrote my query.

    @Nominal Animal

    Code:
    #include <stdio.h>
     
    #define SUM1(a, b) ((int)(a + b))
    #define SUM2(a, b)  (int)(a+b)
     
    int main(void)
    {
        
        printf(" %d " , 4*SUM1(1,2));
        printf(" %d " , 4*SUM2(1,2));
        
        return 0;
    }
    There is no any effect to the results adding or not the two last braces...

    Similarly with the macro that uses the sizeof operator.
    Last edited by Mr.Lnx; 06-18-2013 at 11:41 AM.

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Mr.Lnx
    For me so far the two last braces are not required but I am thinking why the first implementation prefers it.
    I already gave you the reason:
    Quote Originally Posted by laserlight
    The thing is, when defining a macro, those parenthese are usually not extra: they ensure that when the macro is used as a sub-expression, its meaning will not be changed due to some adjacent sub-expression having higher precedence. This risk is fairly low here because cast operators have rather high precedence, but it better to be safe than sorry that you got careless.
    The cast operator is probably at the line where not having those parentheses is fine, yet having those parentheses is good for consistency to ensure that the reader does not wonder if there could be a problem. Any lower in precedence than the cast operator and it is almost certainly a must to use those outer parentheses for grouping when defining a macro like this.

    Quote Originally Posted by Mr.Lnx
    Similarly with the macro that uses the sizeof operator.
    The sizeof operator has even higher precedence than the cast operator. Personally, I would just ditch those outer parentheses for such a case, but if one wants to add them in for consistency, then so be it.

    EDIT:
    Quote Originally Posted by Mr.Lnx
    There is no any effect to the results adding or not the two last braces...
    Try:
    Code:
    #include <stdio.h>
    
    #define FOO1(a) ((int)a)
    #define FOO2(a) (int)a
    
    int main(void)
    {
        int x = 1;
        printf(" %d ", FOO1(x)++);
        printf(" %d ", FOO2(x)++);
    
        return 0;
    }
    Observe that one results in an error message and the other does not.
    Last edited by laserlight; 06-18-2013 at 12:20 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Mr.Lnx View Post
    There is no any effect to the results adding or not the two last braces...
    That is, exactly like laserlight wrote, because the cast operator has higher precedence than arithmetic operators. See the Wikipedia article on Operators in C and C++, and the operator precedence section.

    The counterexample laserlight showed with post-increment and post-decrement (also known as suffix increment and suffix decrement) illustrates the case well:
    Code:
    (int)variable++
    (int)variable--
    evaluate as
    Code:
    (int)(variable++)
    (int)(variable--)
    because the post-increment and -decrement have higher precedence than the type cast. That's why using
    Code:
    #define FOO1(a) ((int)a)
    FOO1(x)++;
    throws an error; it evaluates to ((int)a)++; where the argument of the ++ operator is not an Lvalue (valid value for Left side of an assignment).



    Re-reading the thread, I think both laserlight and I neglected the recommended parentheses around macro arguments, too. The proper definition for an integer sum of two arguments is
    Code:
    #define SUMB(a, b) ((int)(a) + (int)(b))
    and for a sum, cast to integer, is
    Code:
    #define SUMA(a, b) ((int)((a) + (b)))
    Their difference is that the former casts the arguments to ints before summation, the latter after summation. In particular:
    Code:
    SUMB(0.9, 0.9) == 0
    SUMA(0.9, 0.9) == 1
    The parentheses around the macro arguments are important, if the arguments happen to be more complex expressions:
    Code:
    SUMB(0.4 + 0.3, 0.2 + 0.5) == 0
    but without the parentheses around the arguments,
    Code:
    #define BADSUMB(a, b) ((int)a + (int)b)
    BADSUMB(0.4 + 0.3, 0.2 + 0.5) == ((int)0.4 + 0.3 + (int)0.2 + 0.5) == 0.8
    Again, this is because the cast operator has higher precedence than summation, so the cast only affects the leftmost part of the argument expression.

    TL;DR: One should always add an "extra" pair of parentheses around macro definitions, and around each macro argument. Otherwise the operator precedence easily surprises the macro user with unexpected results.

  14. #14
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    357
    First of all thank you very very very much for your time and for your long answers...

    I am ok now. But I have to say my compiler does not complain when it confronts with the following snippet of code :

    Code:
    #include<stdio.h>
    #define FOO1(a) ((int)a)
    
    int main(void)
    {
          int x=1;
         FOO1(x)++;
    
    return 0;
    }
    I am using gcc version 4.4.5 . Anyway thank you again

    Code:
    #include <stdio.h>
    #define SUM(a, b) ((int)(a) + (int)(b))
    
     
    int main(void)
    {
       if( SUM(0.4 + 0.3 , 0.2 + 0.5) == 0 )
       puts("Very good example");
       
        return 0;
    }

  15. #15
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Mr.Lnx View Post
    I have to say my compiler [gcc-4.4.5] does not complain when it confronts with the following snippet of code
    Later versions of GCC do. GCC-4.6.3 reports
    Code:
    mr_lnx.c:7:13: error: lvalue required as increment operand
    GCC 3.4.6 documentation says the following about generalized lvalues:
    A cast is a valid lvalue if its operand is an lvalue. This extension is deprecated.
    Sometime prior to 4.6.3 that extension changed from deprecated to not supported.



    If you look at a slightly related thread from 2011, the correct way to rewrite
    Code:
    size_t  stride;    /* Number of floats to skip */
    anytype *pointer;  /* Points really to a float */
    
    (float *)pointer += stride;
    is to expand the += expression, converting it into an assignment,
    Code:
    pointer = (anytype *)((float *)pointer + stride);
    Note: the pointer arithmetic is done on a pointer to float, which I assume was the original intent. If stride is in bytes, one might use (anytype)((char *)pointer + stride), but the problem then is that some architectures require floats (and other types) to be aligned to two/four/eight/sixteen-byte boundary in memory. (That is solved portably by using memcpy() to copy the value to a locally declared temporary float variable, and using that one instead.)

    I'm considering this related, because casts are a powerful tool you must use correctly, or you risk making your code buggy; and preprocessor macros are just macros that are expanded completely prior to compiling. You can even run
    Code:
    cpp mr_lnx.c
    to see the pre-processed source code.

    So, even if a particular compiler happens to support an extension that some or all casts can be treated as lvalues, you really should not rely on it in C. The correct solution is to expand the expression instead, and to use explicit casts. Sometimes you need to think or do some research to find out what the proper type to cast to is.

    (Hint: with memory amounts, it is usually size_t if never negative, ssize_t otherwise; off_t if file size, and for integer representation of pointers, intptr_t (or long if "stdint.h" is not available). In particular, int can only represent pointers on some architectures like 32-bit x86; it is too small on for example 64-bit x86-64. Many programmers fail to realize that, causing a lot of headaches when porting code to 64-bit architectures.)

    See the C library man pages for current C library function return types. For example, compare C89 ftell() and POSIX.1-2001 ftello() return types.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Casting a 32-bit int as a char array
    By Invariant in forum C Programming
    Replies: 3
    Last Post: 01-28-2010, 07:14 AM
  2. Significance of exit()
    By MK27 in forum C Programming
    Replies: 7
    Last Post: 11-17-2009, 07:03 PM
  3. Replies: 8
    Last Post: 01-23-2008, 04:22 AM
  4. Structures, passing array of structures to function
    By saahmed in forum C Programming
    Replies: 10
    Last Post: 04-05-2006, 11:06 PM
  5. Significance of $
    By tyler4588 in forum Tech Board
    Replies: 3
    Last Post: 07-18-2003, 02:39 AM