5

C header sample.

typedef LPVOID UKWD_USB_DEVICE;

typedef struct _UKWD_USB_DEVICE_INFO {
    DWORD dwCount;
    unsigned char Bus;
    unsigned char Address;
    unsigned long SessionId;
    USB_DEVICE_DESCRIPTOR Descriptor;
} UKWD_USB_DEVICE_INFO, *PUKWD_USB_DEVICE_INFO, * LPUKWD_USB_DEVICE_INFO;

My Understanding

struct defines a structure (the part between {}). The structure's type is _UKWD_USB_DEVICE_INFO. After the closing } UKWD_USB_DEVICE_INFO is an alias to this structure.

Question

What is the purpose of the declarations after that. * PUKD_USB_DEVICE_INFO and *LPUKWD_USB_DEVICE_INFO. Do these pointer aliases mean something different if one is touching the variable and the other has a space between the * and lettering?

Community
  • 1
  • 1
Ccorock
  • 892
  • 12
  • 37

4 Answers4

5

C typedef declarations are understood by analogy with variable declarations.

int a, *b;

declares the values a of type int and b of type int*.

typedef int A, *B;

declares the type A equivalent to int and the type B equivalent to int*. So, just think about what the variable type would be if this was a variable declaration.

So yes, PUKWD_USB_DEVICE_INFO becomes equivalent to struct _UKWD_USB_DEVICE_INFO*.

EDIT

Also, the space does not matter. C is a whitespace language. The extra aliases are not necessary, they are just there to fit with conventions of various projects and APIs that like to call pointer types by names that include P or other substrings. Sometimes these projects end up with multiple conventions over time, so there are multiple aliases. They can also be needed for compatibility reasons when APIs get updated, or between different platforms.

antron
  • 3,749
  • 2
  • 17
  • 23
  • "C is a whitespace language"? Is there a word missing there? – Alex Celeste May 16 '15 at 17:05
  • No, that's deliberate. At least in the 90s, it was common (for me) to see statements like "C is a whitespace language" or "C++ is a whitespace language," followed by an explanation that whitespace in source code is not significant. Perhaps my memory is wrong or this is not modern usage. – antron May 16 '15 at 17:08
1

Yes, it's a pointer alias, you can then use PUKWD_USB_DEVICE_INFO as UKWD_USB_DEVICE_INFO*. Most Windows structs do this:

enter image description here

That L in the third alias stands for long (pointer), and unless I'm much mistaken, it has no meaning in 32/64 bit code - it's likely a leftover from 16 bit stuff, as is the case with that WNDCLASS definition.

user4520
  • 3,401
  • 1
  • 27
  • 50
  • Why would you use more than one alias? Is this for allowing variable sizes of the structure? – Ccorock May 16 '15 at 16:25
  • 1
    typedef'ing a struct is a very poor programming practice. It clutters the code, leads to misunderstandings, makes the code more difficult for humans to understand and clutters the compiler name space. Sadly, Microsoft has not yet determined that they want their code to be simple and straight forward. The result is the confusion seen today in things like their libraries and naming conventions. – user3629249 May 16 '15 at 16:33
  • in the posted struct definition, the key factor is the ',' delimiter. The '*' can be placed anywhere before the symbol name. – user3629249 May 16 '15 at 16:33
  • 1
    @user3629249 Regarding your first comment: why do you think so? I don't see how the absence of `struct` every 10 words would clutter the code, quite the opposite. – user4520 May 16 '15 at 16:42
  • @szczurcio, I have read many many postings where the typedef name is not related to the struct tag name, or uses the same spelling (even capitalization) as the struct tag name and a preponderance of typedef'ing pointers with no indication that the name is a pointer. All of which are bad programming practices. using the actual 'struct tagname' format (and when necessary 'struct tagname *' format leaves no room for misunderstandings. – user3629249 May 20 '15 at 00:42
  • @szczurcio, continuing: in the 'real world' a struct definition and any typedef's are in some header file and the actual usage is in some source file. when there are hundreds of files, it is a real pain to keep researching the same info. A 'struct tagname' immediately tells the reader what they are looking at. When performing maintenance or even debugging old code, readability/clarity/simplicity count for hundreds of hours NOT wasted hunting item definitions located in far off files – user3629249 May 20 '15 at 00:47
1

Are these pointer aliases?

Yes.

Does it mean anything if one is touching the variable and the other has a space between the * and lettering?

No. In C, spaces between tokens have no meaning to the compiler. They merely change the readability for people looking at the code.

I have seen very few code examples online use more than one name after the close of the curly brackets. Any insight on this?

Typically, and in this case in particular, it's done to allow symbol names that may represent different types, but also may not.

You're seeing that on your architecture, a P "pointer" and a LP "long pointer" happen to be the same type.

On a 16-bit architecture, you would be looking at a different header and those types would be different.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
1

This style of definition is common on the Windows platform. In the days of 16 bit segmented architectures, each structure definition typedef had also 2 pointer typedefs for near and far (aka long pointers):

typedef LPVOID UKWD_USB_DEVICE;

typedef struct _UKWD_USB_DEVICE_INFO {
    DWORD dwCount;
    unsigned char Bus;
    unsigned char Address;
    unsigned long SessionId;
    USB_DEVICE_DESCRIPTOR Descriptor;
} UKWD_USB_DEVICE_INFO, NEAR * PUKWD_USB_DEVICE_INFO, FAR * LPUKWD_USB_DEVICE_INFO;

NEAR pointers were 16 bit wide and FAR pointers were 32 bit wide. Most Windows APIs took FAR pointers, and their prototypes used the pointer typedefs. Incidentally, LPVOID was defined this way:

typedef void FAR *LPVOID;

32 bit Windows came out in 1995 and made this obsolete. NEAR and FAR keywords were kept for a while, defined as empty, for compatibility reasons.

Compatibility with 16 bit Windows has long become useless, but the usage still lingers as the typedefs are still in use, but the FAR and NEAR keywords were removed.

The space between * and PUKWD_USB_DEVICE_INFO is ignored, but I agree with you it is rather confusing to put one there.

chqrlie
  • 131,814
  • 10
  • 121
  • 189