locked
Why doesn't DWORD allow conversion to uint32_t RRS feed

  • Question

  • Yes, DWORD is 'unsigned long' and uint32_t is 'unsigned int' 

    1) under 32 bit and 64 bit architecture this results in the same sizes of types, and they are both unsigned, why are they not allowed to be equivalent?


    #include <windows.h>
    #include <stdint.h>
    #include <stdio.h>
    
    
    void f( DWORD *x ) { }
    
    int main( void ) {
    	printf( "sizeof DWORD is %d", sizeof( DWORD ) );
    	printf( "sizeof uint32_t is %d", sizeof( uint32_t ) );
    	{
    		uint32_t x;
    		f( &x );
    	}
    	return 0;
    }

    or

    void *p;
    __stosd( (uint32_t*)p, n, sz / 4 );
    
    
    //Severity	Code	Description	Project	File	Line	Suppression State
    Error	C2664	'void __stosd(unsigned long *,unsigned long,std::size_t)': cannot convert argument 1 from 'uint32_t *' to 'unsigned long *'	bag++	C:\general\build\vs14\sack-d\debug_solution\core\src\memlib\memory_operations.cpp	51	


    doesn't matter, huh?  It's a bug I'll have to deal with for the next 20 years like snprintf.

    Done, just to make sure noone uses stdint and produces portable code that can be used on more than just windows?

    • Edited by d3x0r Monday, August 15, 2016 11:04 PM
    Monday, August 15, 2016 11:01 PM

Answers

  • On 8/15/2016 7:01 PM, d3x0r wrote:

    Yes, DWORD is 'unsigned long' and uint32_t is 'unsigned int'

    1) under 32 bit and 64 bit architecture this results in the same sizes of types, and they are both unsigned, why are they not allowed to be equivalent?

    They aren't the same size on all compilers; e.g. long is typically 64 bit with 64-bit compilers targeting Linux. Then, if one compiler allows this conversion but the other doesn't, it would be more difficult to write portable code.

    doesn't matter, huh?  It's a bug I'll have to deal with for the next 20 years like snprintf.Done, just to make sure noone uses stdint and produces portable code that can be used on more than just windows?

    One wouldn't normally use DWORD in a portable code that can be used on more than just Windows, seeing as one would need to #include <windows.h> to get it defined in the first place.

    • Proposed as answer by Baron Bi Tuesday, August 16, 2016 6:31 AM
    • Marked as answer by Hart Wang Wednesday, August 24, 2016 1:38 AM
    Tuesday, August 16, 2016 1:03 AM
  • And it's only if the code is compiled with C++, the C compiler has no issue.


    C will do implicit casts where C++ will not, but C++ will accomodate explcit
    casts in many cases. e.g. -

    f( (DWORD*)&x );

    f( reinterpret_cast<DWORD*>(&x) );

    - Wayne

    • Proposed as answer by Baron Bi Tuesday, August 16, 2016 6:32 AM
    • Marked as answer by Hart Wang Wednesday, August 24, 2016 1:38 AM
    Tuesday, August 16, 2016 3:32 AM

All replies

  • On 8/15/2016 7:01 PM, d3x0r wrote:

    Yes, DWORD is 'unsigned long' and uint32_t is 'unsigned int'

    1) under 32 bit and 64 bit architecture this results in the same sizes of types, and they are both unsigned, why are they not allowed to be equivalent?

    They aren't the same size on all compilers; e.g. long is typically 64 bit with 64-bit compilers targeting Linux. Then, if one compiler allows this conversion but the other doesn't, it would be more difficult to write portable code.

    doesn't matter, huh?  It's a bug I'll have to deal with for the next 20 years like snprintf.Done, just to make sure noone uses stdint and produces portable code that can be used on more than just windows?

    One wouldn't normally use DWORD in a portable code that can be used on more than just Windows, seeing as one would need to #include <windows.h> to get it defined in the first place.

    • Proposed as answer by Baron Bi Tuesday, August 16, 2016 6:31 AM
    • Marked as answer by Hart Wang Wednesday, August 24, 2016 1:38 AM
    Tuesday, August 16, 2016 1:03 AM
  • On 8/15/2016 7:01 PM, d3x0r wrote:

    Yes, DWORD is 'unsigned long' and uint32_t is 'unsigned int'

    1) under 32 bit and 64 bit architecture this results in the same sizes of types, and they are both unsigned, why are they not allowed to be equivalent?

    They aren't the same size on all compilers; e.g. long is typically 64 bit with 64-bit compilers targeting Linux. Then, if one compiler allows this conversion but the other doesn't, it would be more difficult to write portable code.

    I don't know how to break the quote block.

    DWORD is always ALWAYS unsigned 32 bit.  uint32_t is ... What?  By the CPU is there any difference at all in the instructions generated?  Or any possible way a DWORD and a uint32_t by definition are not exactly the same thign?

    No; you're right, one would think that 'unsigned long' which is used to declare DWORD would be a 64 bit value on some compiler used somewhere.  So that then long long can represent 128 natural.  Right?.  But then it would say if __64_BIT__ Something typedef unsigned short long  DWORD .   Because nit would make it compatible with uint32_t.

    doesn't matter, huh?  It's a bug I'll have to deal with for the next 20 years like snprintf.Done, just to make sure noone uses stdint and produces portable code that can be used on more than just windows?

    One wouldn't normally use DWORD in a portable code that can be used on more than just Windows, seeing as one would need to #include <windows.h> to get it defined in the first place.

    Exactly, so the code written around the interface to the platform is in uint32_t; which makes it standard and supported as of 2010 apparently (only, what 2 decades after I needed it to)

    And it's only if the code is compiled with C++, the C compiler has no issue.

    Same with GCC though, so it appears that there is something in the defintion of C++ language by standard that makes long and int impossible to assign, even if the platform they are on is mechanically the same.

    Tuesday, August 16, 2016 2:41 AM

  • 	printf( "sizeof DWORD is %d", sizeof( DWORD ) );
    	printf( "sizeof uint32_t is %d", sizeof( uint32_t ) );
    

    A cautionary aside:

    The sizeof operator returns a size_t which under VC++ is unsigned int for
    32-bit builds and unsigned __int64 for 64-bit builds. In either case the %d
    format specifier for printf is not correct.

    - Wayne

    Tuesday, August 16, 2016 3:16 AM
  • And it's only if the code is compiled with C++, the C compiler has no issue.


    C will do implicit casts where C++ will not, but C++ will accomodate explcit
    casts in many cases. e.g. -

    f( (DWORD*)&x );

    f( reinterpret_cast<DWORD*>(&x) );

    - Wayne

    • Proposed as answer by Baron Bi Tuesday, August 16, 2016 6:32 AM
    • Marked as answer by Hart Wang Wednesday, August 24, 2016 1:38 AM
    Tuesday, August 16, 2016 3:32 AM

  • 	printf( "sizeof DWORD is %d", sizeof( DWORD ) );
    	printf( "sizeof uint32_t is %d", sizeof( uint32_t ) );
    

    A cautionary aside:

    The sizeof operator returns a size_t which under VC++ is unsigned int for
    32-bit builds and unsigned __int64 for 64-bit builds. In either case the %d
    format specifier for printf is not correct.

    - Wayne

    In any case, since big endian machines failed in general; it'll be a correct output since 2 bits is well within the representation of any form of decimal conversion.  yes %z would be better - there's some expression in stdint.h that defines the size_t format  thank you for staying irrelavent.
    Tuesday, August 16, 2016 3:47 AM
  • And it's only if the code is compiled with C++, the C compiler has no issue.


    C will do implicit casts where C++ will not, but C++ will accomodate explcit
    casts in many cases. e.g. -

    f( (DWORD*)&x );

    f( reinterpret_cast<DWORD*>(&x) );

    - Wayne

    right - so it's part of the strictness of C++ that requires a mismatch error be generated, even if functionally equivalent.  cause you know, reintrepret_cast is also C friendly.   

    which litters code with casts to DWORD *.  

    It should probably just take the literal types and never interpret them as more base types for errors then instead of reporting the thing a type is based on...

    typedef unsigned int a;
    typedef a b;
    typedef b c;
    typedef c d;
    typedef unsigned long e;
    
    void f( d*pd) { 
       e ei = 3;
       f( &ei );
    }
    
    // should say e* is not a d*
    // instead of unsigned int is not unsigned long
    // which it is.

    Tuesday, August 16, 2016 3:53 AM
  • Hi d3x0r,

    have your case been solved? If yes, please help to mark. If no, just feel free to reply us, and we will give you a further solution.

    Your understanding and cooperation will be grateful.

    Best Regards,

    Sera Yu


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.

    Thursday, August 18, 2016 9:15 AM

  • In any case, since big endian machines failed in general; it'll be a correct output 

    Unfortunately, not at all :-( Just when you believe that big endian nuisance is behind, it jump on you out of the Blue (pun intended).  On Windows we are safe, though, Windows is always LE.

    -- pa

    Thursday, August 18, 2016 11:38 AM
  • C will do implicit casts where C++ will not, but C++ will accomodate explcit
    casts in many cases. e.g. -

    f( (DWORD*)&x );

    f( reinterpret_cast<DWORD*>(&x) );

    - Wayne

    More to C++, it has overloads. So, if the function f is used more than once, define an overload:

    void f( DWORD *x) { ... }

    inline void f( uint32_t &x) { f( (DWORD*)&x ); } 

    inline void f( size_t *x) { f( (DWORD*)x ); } 



    • Edited by Pavel A Thursday, August 18, 2016 11:50 AM
    Thursday, August 18, 2016 11:47 AM