Check for a GUID (in C)

I want to check if the GUID structure is empty / all fields are 0. This is the code I wrote:

#include <windows.h>

static BOOL IsEmptyGuid(const GUID * const pGuid)
{
    return \
    (pGuid->Data1 == 0) &&
    (pGuid->Data2 == 0) &&
    (pGuid->Data3 == 0) &&
#ifdef _WIN64
    (*(DWORD64 *)pGuid->Data4 == 0);
#else
    (*(DWORD *)pGuid->Data4 == 0) && (*(DWORD *)(pGuid->Data4 + 4) == 0);
#endif
}

/* GUID definition from MSDN
typedef struct _GUID {
    DWORD Data1;
    WORD  Data2;
    WORD  Data3;
    BYTE  Data4[8];
} GUID;
*/


int main() {
    GUID guid1;
    guid1.Data1 = 0;
    guid1.Data2 = 0;
    guid1.Data3 = 0;
    memset(guid1.Data4, 0x0, 8);

    printf("Result: %u\n", IsEmptyGuid(&guid1));
}

A safer way to check if a field is Data40 is to iterate through each byte and check its value. But I find the code above more expressive.

I would like to know if this is correct? It is safe?

Thank!

+4
source share
2 answers

The code is incorrect. It violates the strict rule of aliases (N1570 §6.5 p7) by causing undefined behavior.

The object must have a stored value, access to which has only an lvalue expression, which has one of the following types: 88)

  • a type compatible with an efficient object type,
  • , ,
  • , , ,
  • , , ,
  • , ( , , )
  • .

88) - , .

, UB , :

DWORD64 * temp = (DWORD64 *)pGuid->Data4; // Allowed, but implementation defined
DWORD64 temp2 = *temp;                    // Undefined behaviour

memcmp .


, , , , .

+3

_WIN64

(*(DWORD *)pGuid->Data4 == 0) && (*(DWORD *)(pGuid->Data4 + 4) == 0);

- - Data4 DWORD (4) 2 DWORD (2 * sizeof(DWORD) == 8)

_WIN64 Data4 DWORD (4), 4 (C_ASSERT(__alignof(GUID)==4)) - (*(DWORD64 *)pGuid->Data4 == 0); 8- . , x64, , , . . . :

BOOL IsEmptyGuid(const GUID * pGuid)
{
    return (pGuid->Data1 == 0) &&
        (pGuid->Data2 == 0) &&
        (pGuid->Data3 == 0) &&
        (*(DWORD *)pGuid->Data4 == 0) && (*(DWORD *)(pGuid->Data4 + 4) == 0);
}

.

, .., UB.


, :

  • Data4 8 ?
  • Data4 8 , GUID?
  • Data4 4 (, pGuid )?
  • 8- ( DWORD) 2 DWORD?

Windows:

// Faster (but makes code fatter) inline version...use sparingly
#ifdef __cplusplus
__inline int InlineIsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
   return (
      ((unsigned long *) &rguid1)[0] == ((unsigned long *) &rguid2)[0] &&
      ((unsigned long *) &rguid1)[1] == ((unsigned long *) &rguid2)[1] &&
      ((unsigned long *) &rguid1)[2] == ((unsigned long *) &rguid2)[2] &&
      ((unsigned long *) &rguid1)[3] == ((unsigned long *) &rguid2)[3]);
}

__inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
    return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

#else   // ! __cplusplus

#define InlineIsEqualGUID(rguid1, rguid2)  \
        (((unsigned long *) rguid1)[0] == ((unsigned long *) rguid2)[0] &&   \
        ((unsigned long *) rguid1)[1] == ((unsigned long *) rguid2)[1] &&    \
        ((unsigned long *) rguid1)[2] == ((unsigned long *) rguid2)[2] &&    \
        ((unsigned long *) rguid1)[3] == ((unsigned long *) rguid2)[3])

#define IsEqualGUID(rguid1, rguid2) (!memcmp(rguid1, rguid2, sizeof(GUID)))

#endif  // __cplusplus

#ifndef __IID_ALIGNED__
    #define __IID_ALIGNED__
    #ifdef __cplusplus
        inline int IsEqualGUIDAligned(REFGUID guid1, REFGUID guid2)
        {
            return ((*(PLONGLONG)(&guid1) == *(PLONGLONG)(&guid2)) && (*((PLONGLONG)(&guid1) + 1) == *((PLONGLONG)(&guid2) + 1)));
        }
    #else // !__cplusplus
        #define IsEqualGUIDAligned(guid1, guid2) \
            ((*(PLONGLONG)(guid1) == *(PLONGLONG)(guid2)) && (*((PLONGLONG)(guid1) + 1) == *((PLONGLONG)(guid2) + 1)))
    #endif // !__cplusplus
#endif // !__IID_ALIGNED__
-5

Source: https://habr.com/ru/post/1682652/


All Articles