1

Note: I know how to solve this. I am writing this question to understand WHY it happens.

Ok, so, I am getting this error C2440 'return': cannot convert from 'const IMAGE_DOS_HEADER *' to 'const PIMAGE_DOS_HEADER'. Can anyone tell me why?

The thing here is that, as you probably know, PIMAGE_DOS_HEADER is defined as typedef IMAGE_DOS_HEADER *PIMAGE_DOS_HEADER so they are basically the same thing.

Here's a simple code that gives that error:

class TestClass
{
public:
    const PIMAGE_DOS_HEADER get_header() const
    {
        return &hdr;
    }

    IMAGE_DOS_HEADER hdr;
};

error image

If I remove the const qualifier from the function (so it becomes const PIMAGE_DOS_HEADER get_header()) or cast the return to PIMAGE_DOS_HEADER then the error goes away. What I dont understand is why it is even happening on the first place given that PIMAGE_DOS_HEADER is IMAGE_DOS_HEADER*

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
Mark
  • 35
  • 4
  • 1
    One is a pointer to a constant integer, the other is a constant pointer to an integer. The difference is whether it is the pointer or the thing it points to that is being declared as `const`. – Harry Johnston Aug 18 '16 at 04:17
  • This explains it a little. Typedefing pointers leads to heartache. http://stackoverflow.com/questions/6609422/shorthand-typedef-pointer-to-a-constant-struct/660954 – Retired Ninja Aug 18 '16 at 04:17
  • 1
    @RetiredNinja tell that to Microsoft then... I don't know why they have these typedefs, but I can think of two possible reasons: 1) to simplify the lives of early Pascal programmers where a pointer typedef is common (and traditionally there is no `const`-pointer/pointer-to-`const` to throw these off, though I don't know if Borland introduced one into their variants), or 2) to save typing back in the 16-bit world when there were both "near" and "far" pointer types (that's why there's `LPxxx` everywhere in the Windows API comes from; the `L` indicates a far pointer). – andlabs Aug 18 '16 at 04:43
  • A lot of Microsoft typedefs have const versions, e.g. `LPCWSTR`. Guess this one doesn't. – Jonathan Potter Aug 18 '16 at 04:47
  • @HarryJohnston That cleared it up a bit. Thank you. I can see the problem now. – Mark Aug 18 '16 at 05:07
  • @andlabs: An artifact of early C's syntax rules: To use `struct X {};` you had to repeat the `struct` keyword, i.e. `struct X* x;`. You couldn't just use the structure tag name, i.e. `X* x;` (which is legal today). Observe that there's a `typedef` for the structure itself, not just pointers to it. – IInspectable Aug 18 '16 at 08:35
  • @IInspectable I know that; I was talking about why Windows has the pointer typedefs as well. – andlabs Aug 18 '16 at 12:41
  • 2
    @andlabs: The typedefs for pointers were really more important, and it wasn't just about saving a few keystrokes. The issue was one of correctness (far pointers vs. near pointers). C implicitly converts between all pointer types. Passing a near pointer to an API expecting a far pointer would happily compile, only to blow up at runtime. – IInspectable Aug 18 '16 at 13:32
  • @IInspectable good to know; thanks. – andlabs Aug 18 '16 at 13:51

0 Answers0