Thread: Make int64 from two int32

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    77

    Make int64 from two int32

    Hello dear experts!
    I've done recently the basic exercise of getting a file size using the standard Win32 function GetFileSizeEx. It returns fine up to 2GB (included), and that was good enough for what I need.
    I've tried , just to test, to get file sizes larger than than, in the max 64 bit representation spectrum. I've used this time another method to get the file information from its structure. This structure stores the lower and the upper file size in two int32. I've casted both in _int64, then shifted the upper with 32 positions to the left (<<32), then made an addition of the two into an _int64. And got a bad result, different from the real one. Additional question: does itoa() applies also for int64?
    Many thanks!

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> This structure stores the lower and the upper file size in two int32. I've casted both in _int64, then shifted the upper with 32 positions to the left (<<32), then made an addition of the two into an _int64.

    You don't want to add them - simply OR them together (after shifting, of course).

    >> Additional question: does itoa() applies also for int64?

    No, but many systems support atoi64 or similar, and strtoll might even work "as is". If nothing else, coding a conversion function should be fairly straightforward.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    77
    Thanks, good idea, I'll try.

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Just in case you can't find a conversion function, this should work in most cases (not locale-sensitive, though):

    Code:
    _int64 atoi64( const char* str )
    {
        _int64
            tmp,
            dig,
            end, 
            beg =  0,
            neg = 0,
            val = 0;
        if( ( end = strlen( str ) ) == 0 )
            return 0;
        while( isspace( str[ beg ] ) && beg != end )
            ++beg;
        while( --end != 0 && isspace( str[ end ] ) )
            continue;
        if( end <= beg )
            return 0;
        if( tolower( str[ end ] ) == 'h' ) // hex
        {
            if( --end < beg )
                return 0;
            for( ;; )
            {
                dig = tolower( str[ beg ] );
                if( isdigit( dig ) )
                    tmp = dig - '0';
                else if( isalpha( dig ) && dig <= 'f' )
                    tmp = 10 + ( dig - 'a' );
                else
                    return 0;
                val *= 16;    
                val += tmp;
                if( beg++ == end )
                    break;
            }
        }
        else if( str[ beg ] == '0' ) // oct
        {
            if( end < ++beg )
                return 0;
            for( ;; )
            {
                dig = str[ beg ];
                if( !isdigit( dig ) || dig >= '8' )
                    return 0;
                val *= 8;    
                val += dig - '0';
                if( beg++ == end )
                    break;
            }        
        }
        else // dec
        {
            if( str[ beg ] == '-' )
            {
                ++beg;
                neg = 1;
            }
            else if( str[ beg ] == '+' )
                ++beg;
            if( end < beg )
                return 0;
            for( ;; )
            {
                dig = str[ beg ];
                if( !isdigit( dig ) )
                    return 0;
                val *= 10;
                val += dig - '0';
                if( beg++ == end )
                    break;
            }
            if( neg )
                val = -val;
        }    
        return val;    
    }
    It should be bug-free, but I only ran a few simple tests on it, so you might want to do some testing of your own if you decide to use it.

    EDIT:
    Whoops, the end <= beg comparison will actually reject single-digit input. Corrected.
    Last edited by Sebastiani; 08-16-2009 at 05:11 AM.

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    77
    Thanks for the conversion function!
    But I've just tried to use OR instead of + and the result is the same, ie wrong; btw, the way addition is implemented in assembler, OR and + should be alike for positive integers.
    Here is my code, I may miss something, since it's certain we should be able to get any Windows file size because Explorer displays it from the same data structure that I'm using below:

    Code:
    bool FileSizeByDataStructure (char* fileName)
    {
    	WIN32_FILE_ATTRIBUTE_DATA fileData;
    
    	__int64  m_Filesz;
    	__int64 m_SizeLow;
    	__int64 m_SizeHigh; 
    
    	if (GetFileAttributesEx(fileName, GetFileExInfoStandard, &fileData))
    	{
    		m_SizeLow = (__int64)fileData.nFileSizeLow;
    		m_SizeHigh = ((__int64 )fileData.nFileSizeHigh) << 32;
    		m_Filesz = m_SizeHigh | m_SizeLow;
    		// m_Filesz = (((__int64 )fileData.nFileSizeHigh) << 32) + (__int64)fileData.nFileSizeLow;
    	}
    
    	printf("\nFile size: %ld\n", m_Filesz);
    
    	return true;
    }

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> the way addition is implemented in assembler, OR and + should be alike for positive integers.

    Yep, you're right. As long as the bits aren't overlapping (as in this case) the result would be the same.

    >> But I've just tried to use OR instead of + and the result is the same, ie wrong;

    It should work. Perhaps your printf can't handle _int64? Test it with something like this:

    Code:
    _int64 i = 4294967296LL;
    printf("%d\n", i);
    It could also be due to the fact that integral parameters passed to printf may be implicitly converted to int, thus truncating the value. Also, the standard specifies that the result of a shift is an int, although it seems a compiler that supports _int64 should account for that.

    And by the way, there was a minor bug in the function I posted, but it's been fixed.

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    I guess you could test the shift with this:

    Code:
    _int64 i = (_int64)0x80000000 << 1;
    printf("%d\n", i); // should print 4294967296

  8. #8
    Registered User
    Join Date
    Oct 2008
    Posts
    77
    Right, the error was in the printf format. For other guys reference, here is the right one for displaying _int64:

    Code:
    printf("\nFile size: %I64d\n", m_Filesz);
    I realize I need a conversion from _int64 to char*[], like itoa(), not atoi(). If u have some handy I appreciate, if not I'll do one myself.
    Wrapping-up, thanks a lot for the help!

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> If u have some handy I appreciate, if not I'll do one myself.

    This should work (not thoroughly tested, though):

    Code:
    char* itoa64( _int64 val, char* str, _int64 rad )
    {
        int
            neg = 0;
        char 
            tmp,
            * seq = str,
            * ptr = str,
            tab[ ] = 
        {
            '0', '1', '2', '3', '4', '5', '6', '7', 
            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
        };        
        if( val < 0 )
        {
            val = -val;
            neg = 1;
        }    
        if( rad == 10 || ( ( rad == 8 || rad == 16 ) && !neg ) )
        {
            if( rad == 16 )
                *ptr++ = 'h';
            do
            {
                *ptr++ = tab[ val % rad ];
                val /= rad;
            }
            while( val );
            if( rad == 8 )
                *ptr++ = '0';
            else if( neg )
                *ptr++ = '-';
        }    
        *ptr = 0;
        while( --ptr > seq )
        {
            tmp = *ptr;
            *ptr = *seq;
            *seq++ = tmp;
        }    
        return str;
    }
    Last edited by Sebastiani; 08-16-2009 at 06:37 AM.

  10. #10
    Registered User
    Join Date
    Sep 2008
    Location
    Toronto, Canada
    Posts
    1,834
    In Microsoft Visual Studio
    Code:
    char * _i64toa(__int64 value, char *str, int radix);

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Establishing 'make clean' with GNU make
    By Jesdisciple in forum C Programming
    Replies: 9
    Last Post: 04-11-2009, 09:10 AM
  2. How to make a Packet sniffer/filter?
    By shown in forum C++ Programming
    Replies: 2
    Last Post: 02-22-2009, 09:51 PM
  3. HELP!wanting to make full screen game windowed
    By rented in forum Game Programming
    Replies: 3
    Last Post: 06-11-2004, 04:19 AM
  4. make all rule
    By duffy in forum C Programming
    Replies: 9
    Last Post: 09-11-2003, 01:05 PM
  5. Replies: 6
    Last Post: 04-20-2002, 06:35 PM