Thread: integer constant data types

  1. #1
    Registered User
    Join Date
    Mar 2009
    Posts
    48

    integer constant data types

    Hi,

    I have couple of basic questions about data types for integer constants in C.
    In a fragment of code like the following:
    Code:
    long i = 10;
    I want to confirm the processing of this simple assignment statement inside compiler. I will state my understanding first: compiler sees the integer constant 10, it is unsuffixed decimal so compiler checks if 10 can fit into the range: int->long->unsigned long (assuming ISO C90, not C99). 10 fits into int, so compiler allocate 4 bytes(assuming machine is 32-bit) to store 10 with type as int. This storage space for storing 10 might be a register or some place temporarily. Up to now is the processing of the integer constant 10. Then continue to the assignment, 10 is promoted from int to long because i is long, and assigned to i.

    If the processing is like the above, my questions are:
    1. What's the internal data type used by compiler (gcc or any) when dealing with such situation? Compiler must have an internal data type to store 10 when trying to figure out its data type (int, long, unsigned long). Is this data type the biggest one? For example, if the biggest uses 8 bytes, then when starting to process every integer constant, it is stored in this 8-byte data type. Then to check against int, if not fit, check against long, then unsigned long. If internal data type uses the biggest one, what if integer constant is too large to hold inside compiler?

    2. What's the use of the data type of an integer constant?
    I can only guess two points:
    1) compiler assign storage to the constant according to its type. For example, the temporary storage for 10, its size is 4 bytes because the type of 10 is int.
    2) when an integer constant is in an arithmetic operation, its type is used for type conversion among operands and to determine result type. For example, result for 10*10 is int and result for 10*10ul is unsigned long.
    Is there any use I don't notice?

    3. I searched the following example on the web:
    Code:
    on KEIL--51 (2 bytes for int, 4 bytes for long)
    long totalsec;
    totalsec =  60* 60 * 24 * 365;      //result is  0x3380, wrong
    totalsec =  60ul* 60 * 24 * 365;  //result is  0x1E13380, correct
    
    on KEIL_ARM  (4 bytes for int, 4 bytes for long)
    long totalsec;
    totalsec =  60* 60 * 24 * 365;      //result is 0x1E13380, correct
    totalsec =  60ul* 60 * 24 * 365;  //result is 0x1E13380, correct
    So on KEIL--51, the first example, int range is [-32768, +32767], 60*60*24 is 86400, which is already out of the range before multiplying 365. 86400 is truncated before multiplying 365 or is stored in the internal biggest data type and continue to multiply 365, the final result 31536000 is still stored in this internal data type. At last, it is converted to long. But if this way, the first example on KEIL--51 should be correct. So there must be truncation before assignment and no the internal biggest data type?

    Actually I am quite confused with integer constant data type in C. I don't understand exactly its processing by compiler and why every code like
    Code:
    #define SECONDS_PER_YEAR (60*60*24*365)UL
    has to have suffixes UL.
    I really appreciate it if anyone can help me the correct and detailed way about the (integer) constant data type.

    THANK you very much!!

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    The web example you found is not standard C code... Not sure what it is.

    Your compiler's documentation should detail the sizes and ranges of your various types so your most accurate information will come from there.
    If you want to be real picky about variable sizes (like me) you can include stdint.h, the best way to view it's contents is to open it in notepad or inside your IDE... but don't change anything!

    And, you shouldn't really give a crap how the compiler decides what to do with a variable intializer like you've described. It's actually up to you as the programmer to select a data type large enough to hold the value. (10, for example, would even fit in a char type)

    You should also know that it's not a constant unless you say it's a constant...
    Code:
    const int fraggle = 10;
    And last of all the one nobody wants to hear... C has *absolutely no run time error checking*. It is 100% on you to write code that doesn't screw up.

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    if i understand your question, you are mixing up what happens at compile time with what happens at runtime. simplistically, a compiler has 2 phases : lexical scanner and parser. the lexical scanner picks out the tokens one by one and stores them internally without caring how it is used. the compiler lexical scanner will recognize the type of '10' and store it internally at compile time and as CommonTater says, it doesn't matter how. if the number was '1000000000000' the scanner will handle it differently or issue an error. at the point of reading the program text '10', it doesn't care anything about what you are doing with the value later on and that has nothing to do with runtime code. then when the compiler parser uses the grammar to parse the assignment statement it will figure out what promotions to use if any. none of this is happening at runtime. all at compile time. at run time all you will get is a single instruction store of a constant 10 into the your int variable.

  4. #4
    Registered User
    Join Date
    Mar 2009
    Posts
    344
    Unless you tell it otherwise, the compiler will assume you're doing math using ints. That's true whether or not it is using variables or constants. The result is truncated so it fits in an int before it's then assigned to a long :

    totalsec = 60* 60 * 24 * 365;

    The result of the multiplication is 31536000. This is too long to fit in a 16-bit int (the default size since you didn't tell it otherwise), so it's shrunk down until it does fit. In this case, by dropping the upper bits to get 13184. Now the compiler sees you want to assign it to a long, and just copies this truncated value into the long. Since it's already thrown out the upper bits to make it fit in an int, the value doesn't change.

    Note that if an int were 32 bits (4 bytes), none of the intermediate results would be truncated because they all fit in a 32-bit value. Then this value is converted into a long (which changes nothing, since ints and longs are the same size in your example) and the value gets copied over.

    Edit

    #define SECONDS_PER_YEAR (60*60*24*365)UL

    This won't work. It'll do the math inside the ()s as an int and then convert it to an unsigned long. Try

    #define SECONDS_PER_YEAR (60UL*60*24*365)

    instead.

    If the compiler sees that any part of the expression is bigger than an int, it uses that larger size to do the intermediate calculations. So

    60ul * 60 * 24 * 365

    makes the expression work since immediately the compiler sees that the intermediate result should be a a 4-byte unsigned long. Since all of the intermediate values fit into a 32-bit number, the calculation works no matter what the size of int.

    Note that this also causes problems with floating point values.

    float x = 1/2 assigns 0 to x. Same reason as above. Both 1 and 2 are integer constants, so the compiler treats 1/2 as an integer division. 1/2 = 0 with a remainder of 1, but since the math is done on an integer result, the answer is just 0. This then gets converted into a float (0.0) and assigned to x. The way to fix this is to tell the compiler that you want to do the math as something other than the default as an integer : ((float)1)/2, or 1.0/2 (or 1/2.0) in shorthand, to make one of the constants a floating point value rather than the default int.

    As I said, this works for both constants and variables, so, for example in

    Code:
    int a = 1;
    int b = 2;
    float x = a / b;
    x = 0 for exactly the same reason as it does for float x = 1/2

    http://publications.gbdirect.co.uk/c...rithmetic.html has a description of how this works, including a list of how C figures out what the type of an expression should be based on the types of the various parts of the equation.
    Last edited by KCfromNC; 11-22-2011 at 09:46 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 11-15-2011, 08:31 PM
  2. Copying constant amount of data
    By TriKri in forum C++ Programming
    Replies: 16
    Last Post: 07-12-2008, 06:32 AM
  3. Replies: 7
    Last Post: 06-01-2008, 07:47 AM
  4. integer constant is too large for type
    By Abda92 in forum C++ Programming
    Replies: 8
    Last Post: 02-09-2008, 11:47 AM
  5. integer to constant char w/o using itoa()
    By kes103 in forum C++ Programming
    Replies: 1
    Last Post: 01-06-2003, 10:42 PM