1

I read someone's code.

#include "send_input.h"

#include <stdlib.h>
#include <math.h>
#include <windows.h>
#include <winuser.h>

/* function definition
 * function definition
 * function definition
 * ...
 */

I found windows.h at 'C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um'

#if defined(RC_INVOKED) && !defined(NOWINRES)

#include <winresrc.h>

#else
/* ... */
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
/* ... */
#endif /* RC_INVOKED */

windows.h has #include <winuser.h>(so the former is superset of the latter) although it depends on #if defined(RC_INVOKED) && !defined(NOWINRES). Is there a special meaning in below fragment? Is it just style matter to emphasize functions in winuser.h are frequently used?

#include <windows.h>
#include <winuser.h>
op ol
  • 705
  • 4
  • 11
  • 3
    The code is wrong, obviously. The original idea was to only `#include ` and maybe control what got included with `#define`s. However knowledge of what is sub-included by `windows.h` has obviously leaked and people feel free to only include those directly. I guess if it works you can't argue with it. But it is never correct to include both: just a waste of compilation time. In this case `winuser.h` has already been included so the compiler just has to read it all again and ignore it, as determined by its include-guards. – user207421 Jun 12 '21 at 03:31
  • 1
    [`RC_INVOKED`](https://learn.microsoft.com/en-us/windows/win32/menurc/predefined-macros) – RbMm Jun 12 '21 at 06:50
  • @use Yes, that is a valid opinion. As with all opinions, they can fail to coincide with reality. In this case, there is **absolutely no reason at all** for a compiler to touch a header file after it has been included once already, and the compiler has determined that including it a second time would be a no-op. If you strongly disagree, please explain yourself why a compiler would be strictly forced into reading a header a second time. – IInspectable Jun 12 '21 at 10:22
  • @IInspectable only if header containing [`#pragma once`](https://learn.microsoft.com/en-us/cpp/preprocessor/once?view=msvc-160) *compiler won't open and read the file again after the first #include of the file in the translation unit*. otherwise compiler **must** again process include file. in most case this will be faster compare first time - if exist include guard idiom for part content of include. this guarded part will be not processed again. but anyway need reread header file. – RbMm Jun 12 '21 at 12:29
  • @rbm To safe you some time, this is verbatim from the [link](https://learn.microsoft.com/en-us/cpp/preprocessor/once?view=msvc-160) you referenced in an attempt to prove me wrong: *"The compiler recognizes the include guard idiom, and implements the multiple-include optimization **the same way** as the `#pragma once` directive \[...\]"*. – IInspectable Jun 12 '21 at 13:52
  • @IInspectable guard idiom only for part of file and need re-read file or cache it content in memory for check this. the `#pragma once` is per file and need not re-read it more in this case. and for test do next for instance - `#include #include #include ` - why error will be in this case ? – RbMm Jun 12 '21 at 14:01
  • @IInspectable - *Show me the rule in the language specification that requires a compiler to re-read a header file* - how about think yourself, but not only read documentation ? compiler **must** process file again, if no *#pragma once* in it. for process file again - need or re-read it or hold in memory it content after first read – RbMm Jun 12 '21 at 14:05
  • @rbm Did you not read the link you posted, or did you fail to comprehend the information therein? Read it again, and re-evaluate whether *"compiler **must** process file again, if no `#pragma once` in it."* is a correct statement (hint: it isn't). – IInspectable Jun 12 '21 at 14:14
  • @IInspectable - and ? i and write exactly this - when no #pragma once in header file - compiler will process file **again** – RbMm Jun 12 '21 at 14:19
  • @IInspectable - you have big problems with logical and independent thinking. i show you very simply example - `#include #include #include ` - compiler **always must** process include file again and again, if no #pragma once in it – RbMm Jun 12 '21 at 14:22
  • @IInspectable - absolute concrete question - `#include #include #include ` compiler will process *winioctl.h* 1 or 2 time ? – RbMm Jun 12 '21 at 14:23
  • and compiler can do conditional processing based on macros . if write `#ifndef XXX #define XXX #endif` compiler process this only once ( until `#undef XXX` not be) - but this not related to file processing. only *#pragma once* stop from again process file. so you absolute wrong – RbMm Jun 12 '21 at 14:27
  • @rbm There *are* situation, where the compiler will need to re-read a header file. You provided some examples where this is the case. The consequence if this **is not**, that a compiler is **always required** to re-read a header. In the vast majority of cases it will not, and does not. Irrespective of whether the header contains a `#pragma once` director **or uses the guard idiom**. – IInspectable Jun 12 '21 at 14:30
  • @IInspectable - *In the vast majority of cases it will not, and does not. Irrespective of whether the header contains a #pragma once director or uses the guard idiom.* - absolute false - from where compiler can know that some guard idiom exist in file ?! need look to file content. so need or hold it in memory or re-read ( re-read not mean access disk - really faster from fs cache). the *#pragma once* - absolute different thing. compiler mantain list of headers which he already process and if some header *#pragma once* he simply mark this header and not process more – RbMm Jun 12 '21 at 14:35
  • @rbm Why do you post a [link](https://learn.microsoft.com/en-us/cpp/preprocessor/once?view=msvc-160) you neither read or comprehended? This time around, do read it. If you do not arrive at the conclusion: *"Oh hey, I might actually be wrong here"*, read it again. – IInspectable Jun 12 '21 at 14:44
  • *#pragma once* - per file, when conditional compilations (guard idiom) not related to any file at all. it can not prevent from processing file again. it prevent from process guarded block in file again. but first need anyway access file content again. in case *#pragma once* - not need do this – RbMm Jun 12 '21 at 21:45
  • @rbm Feel free to [share](https://stackoverflow.com/q/67955853/1889329) your [profound](https://stackoverflow.com/a/45411743/1889329) insights. – IInspectable Jun 13 '21 at 07:38
  • 1
    @RbMm *"can not prevent from processing file again"* Why not? If the compiler can remember that it seen `#pragma once` in a header, what stops it from remembering that it seen a regular scope guard in there? Your [link](https://learn.microsoft.com/en-us/cpp/preprocessor/once?view=msvc-160) even says so in plain text: *"no advantage to use of both the include guard idiom and #pragma once in the same file. The compiler recognizes the include guard idiom, and implements the multiple-include optimization the same way as the #pragma once directive"* – HolyBlackCat Jun 13 '21 at 07:38
  • @HolyBlackCat - because `#pragma once` exactly per file - compiler maintain list of headers which he already process and if header include `#pragma once` - it can set flag for this header - not process it again. but in case conditional compilation - how it related to file ?! try think yourself. compiler need include header anyway. simply it not process block in condition – RbMm Jun 13 '21 at 08:11
  • @RbMm It can have a map, with file path as key and the name of guard macro as value. It would be filled when the file is first included. Subsequent inclusions can check this map first, before accessing the files. – HolyBlackCat Jun 13 '21 at 08:20
  • @HolyBlackCat - but how guard macro related to file name ?! so called "guard" macro - usual condition macro. file can containing any count of this macro - 0,1, 2.. any. this is simply block under conditional - not more. compiler not process this block again. but not related to file – RbMm Jun 13 '21 at 08:21
  • @IInspectable - sure. will do it – RbMm Jun 13 '21 at 08:23
  • @RbMm Yes, this is a usual conditional macro. But I heard about compilers recognizing a special case where such conditional block spans the whole file, and optimizing this in the way I explained. Whether or not the whole file is wrapped in an include guard is determined when the file is processed (included) the first time. – HolyBlackCat Jun 13 '21 at 08:24
  • @HolyBlackCat - *special case where such conditional block spans the whole file* - can you describe this case ? how compiler select this ? – RbMm Jun 13 '21 at 08:26
  • @RbMm It should be straightforward? Presumably when the file is first included, the preprocessor checks that it starts with `#ifndef X` `#define X`, and there is nothing after corresponding `#endif`. If it is the case, the file is assumed to use the traditional include guard, and can be optimized in this manner. – HolyBlackCat Jun 13 '21 at 08:28
  • @rbm The link to Microsoft's documentation even explains the conditions used by MSVC to determine the include guard pattern. Now would be a good time to read that link again. – IInspectable Jun 13 '21 at 08:33
  • @HolyBlackCat -no - do simply test - "#undef X" and include header again ! `#ifndef _test_ #define _test_ int a = 0; #endif` and `#include "test.h" #undef _test_ #include "test.h"` – RbMm Jun 13 '21 at 08:34
  • @RbMm Uhh, please read my [comment](https://stackoverflow.com/questions/67945342/when-should-i-write-both-winuser-h-and-windows-h-header?noredirect=1#comment120112792_67945342) again. I didn't say that the presence of this pattern alone disables double inclusion. It merely lets compiler construct a map to quickly tell which file has which include guard (if any). When you include the file second time, that map would be used to see that `test.h` uses `_test_` as guard (without the need to access the file). Compiler then checks that the macro is not defined, and starts processing the file. – HolyBlackCat Jun 13 '21 at 08:42
  • 1
    @HolyBlackCat - give me 30 min +/- - i post self answer under iinspectable question - hard do this in comment format – RbMm Jun 13 '21 at 08:45
  • 1
    @HolyBlackCat - however experiment with [`/showIncludes`](https://learn.microsoft.com/en-us/cpp/build/reference/showincludes-list-include-files?view=msvc-160) show that you correct, if nothing outside single condition macro. – RbMm Jun 13 '21 at 08:56
  • @rbm Those able to read have come to the same conclusion TWENTY-TWO comments ago. Might want to put more emphasis into your reading comprehension skills, and only consider thinking as a last resort. Bear in mind that when you start thinking, you are probably wrong, most of the time. – IInspectable Jun 13 '21 at 09:24
  • @IInspectable - documentation say that *#ifndef HEADER_H_* equivalently to *#if !defined HEADER_H_* but no in test – RbMm Jun 13 '21 at 09:25
  • @HolyBlackCat - i post https://stackoverflow.com/a/67956878/6401656 . you partially(or full) correct in self assumption – RbMm Jun 13 '21 at 09:46
  • @rbm The exercise isn't to find a situation where the compiler cannot apply the optimization. The exercise is to find **a single case** where it can, to prove your statement (*"a compiler can **never** do X"*) wrong. I suppose we have done that and can conclude that you are wrong. – IInspectable Jun 13 '21 at 10:06
  • @IInspectable - again - so called guard statement **by logic** related to **block** of code, but not to file as a whole. no **explicit** option to say - macro *_xyz_* must be guard **file** *x.h*. but *CL* really do **implicit** optimization in some case. and despite in msdn - *#ifndef HEADER_H_ // equivalently, #if !defined HEADER_H_* by fact this is **false** - already `#if !defined HEADER_H_` not guard file from second time including. – RbMm Jun 13 '21 at 10:11

1 Answers1

1

The rules are simple: You include the header files you need. The documentation for any API call includes information on which header to include.

I don't know whether it is always an error to include both <windows.h> and <winuser.h>. You would have to consult the documentation for every symbol used by the code to verify.

As noted, though, the Windows SDK header files aren't exclusively used by a C or C++ compiler. The Resource Compiler is another client of those header files. Including <winuser.h> after <windows.h> is potentially not even superfluous in this case.

IInspectable
  • 46,945
  • 8
  • 85
  • 181