Header files in windows programming

C — Header Files

A header file is a file with extension .h which contains C function declarations and macro definitions to be shared between several source files. There are two types of header files: the files that the programmer writes and the files that comes with your compiler.

You request to use a header file in your program by including it with the C preprocessing directive #include, like you have seen inclusion of stdio.h header file, which comes along with your compiler.

Including a header file is equal to copying the content of the header file but we do not do it because it will be error-prone and it is not a good idea to copy the content of a header file in the source files, especially if we have multiple source files in a program.

A simple practice in C or C++ programs is that we keep all the constants, macros, system wide global variables, and function prototypes in the header files and include that header file wherever it is required.

Include Syntax

Both the user and the system header files are included using the preprocessing directive #include. It has the following two forms −

This form is used for system header files. It searches for a file named ‘file’ in a standard list of system directories. You can prepend directories to this list with the -I option while compiling your source code.

This form is used for header files of your own program. It searches for a file named ‘file’ in the directory containing the current file. You can prepend directories to this list with the -I option while compiling your source code.

Include Operation

The #include directive works by directing the C preprocessor to scan the specified file as input before continuing with the rest of the current source file. The output from the preprocessor contains the output already generated, followed by the output resulting from the included file, followed by the output that comes from the text after the #include directive. For example, if you have a header file header.h as follows −

and a main program called program.c that uses the header file, like this −

the compiler will see the same token stream as it would if program.c read.

Once-Only Headers

If a header file happens to be included twice, the compiler will process its contents twice and it will result in an error. The standard way to prevent this is to enclose the entire real contents of the file in a conditional, like this −

This construct is commonly known as a wrapper #ifndef. When the header is included again, the conditional will be false, because HEADER_FILE is defined. The preprocessor will skip over the entire contents of the file, and the compiler will not see it twice.

Computed Includes

Sometimes it is necessary to select one of the several different header files to be included into your program. For instance, they might specify configuration parameters to be used on different sorts of operating systems. You could do this with a series of conditionals as follows −

But as it grows, it becomes tedious, instead the preprocessor offers the ability to use a macro for the header name. This is called a computed include. Instead of writing a header name as the direct argument of #include, you simply put a macro name there −

SYSTEM_H will be expanded, and the preprocessor will look for system_1.h as if the #include had been written that way originally. SYSTEM_H could be defined by your Makefile with a -D option.

Header files (C++)

The names of program elements such as variables, functions, classes, and so on must be declared before they can be used. For example, you can’t just write x = 42 without first declaring ‘x’.

Читайте также:  Курсор плюс для windows 10

The declaration tells the compiler whether the element is an int , a double , a function, a class or some other thing. Furthermore, each name must be declared (directly or indirectly) in every .cpp file in which it is used. When you compile a program, each .cpp file is compiled independently into a compilation unit. The compiler has no knowledge of what names are declared in other compilation units. That means that if you define a class or function or global variable, you must provide a declaration of that thing in each additional .cpp file that uses it. Each declaration of that thing must be exactly identical in all files. A slight inconsistency will cause errors, or unintended behavior, when the linker attempts to merge all the compilation units into a single program.

To minimize the potential for errors, C++ has adopted the convention of using header files to contain declarations. You make the declarations in a header file, then use the #include directive in every .cpp file or other header file that requires that declaration. The #include directive inserts a copy of the header file directly into the .cpp file prior to compilation.

In Visual Studio 2019, the C++20 modules feature is introduced as an improvement and eventual replacement for header files. For more information, see Overview of modules in C++.

Example

The following example shows a common way to declare a class and then use it in a different source file. We’ll start with the header file, my_class.h . It contains a class definition, but note that the definition is incomplete; the member function do_something is not defined:

Next, create an implementation file (typically with a .cpp or similar extension). We’ll call the file my_class.cpp and provide a definition for the member declaration. We add an #include directive for «my_class.h» file in order to have the my_class declaration inserted at this point in the .cpp file, and we include to pull in the declaration for std::cout . Note that quotes are used for header files in the same directory as the source file, and angle brackets are used for standard library headers. Also, many standard library headers do not have .h or any other file extension.

In the implementation file, we can optionally use a using statement to avoid having to qualify every mention of «my_class» or «cout» with «N::» or «std::». Don’t put using statements in your header files!

Now we can use my_class in another .cpp file. We #include the header file so that the compiler pulls in the declaration. All the compiler needs to know is that my_class is a class that has a public member function called do_something() .

After the compiler finishes compiling each .cpp file into .obj files, it passes the .obj files to the linker. When the linker merges the object files it finds exactly one definition for my_class; it is in the .obj file produced for my_class.cpp, and the build succeeds.

Include guards

Typically, header files have an include guard or a #pragma once directive to ensure that they are not inserted multiple times into a single .cpp file.

What to put in a header file

Because a header file might potentially be included by multiple files, it cannot contain definitions that might produce multiple definitions of the same name. The following are not allowed, or are considered very bad practice:

  • built-in type definitions at namespace or global scope
  • non-inline function definitions
  • non-const variable definitions
  • aggregate definitions
  • unnamed namespaces
  • using directives

Use of the using directive will not necessarily cause an error, but can potentially cause a problem because it brings the namespace into scope in every .cpp file that directly or indirectly includes that header.

Sample header file

The following example shows the various kinds of declarations and definitions that are allowed in a header file:

Header files and multi-file sources in C language

As C programming language is very old, it has obsolete and not intuitive capabilities in creating program that consists from multiple files with source code. In this tutorial we’ll learn how to build such program and learn about the role of header files in C language.

Читайте также:  Центр производительности windows 10

Header files in C language

When we run compiler, it compiles the source code files separately (if we have more than one) into object files. Object files contains binary code. After that, another program, that is called linker, links object files together into executable file.

In our first program we saw such string:

#include is one of the examples of preprocessor directives. Preprocessor directives are executed before compiler starts it’s work. #include inserts contents of the specified file at the place where include directive is. So, stdio.h is a file. C language requires including of header files.

Header files contains «description» of functionality. The actual implementation is located in another binary file. I.e. to use functionality of external source code file we need to include header file that describes what this file can do. stdio.h contains function declarations that are related to input/output.

Include directive can behave different depending of syntax:

When we enclose file in <> preprocessor will try to find the file in directories where compiler stores it’s standard libraries. When we use «», preprocessor will check first directory with the source code of your program and when will try to search in standard library directories. You need to use «» when you include your own header files.

Header files mostly contains declarations of functions. So, when you use external function in your own code, compiler sees that there is the declaration and what arguments function can receive. Later linker will link the binary code that contains definition of function to your own code.

Multi-file program in C language

Let’s try it. We’ll have file with the main function, the file that will have another function and header file for this function.

We have separate file hello.c that contains definition of function hello that prints text. Pay attention that we included in this file stdio.h as we use function printf. File hello.h contains declaration of function. In the file multi-file.c we include hello.h and later we use function hello.

Compiling multiple source files

Now let’s compile our program with gcc:

We use parameter -o to set the output executable file and after that we list all source code files. We don’t need to list header files, preprocessor will find them automatically.

Conclusion

Our programs will become larger and larger, so we’ll need to divide code into separate files and now we know how to do it.

Using the Windows Headers

The header files for the Windows API enable you to create 32- and 64-bit applications. They include declarations for both Unicode and ANSI versions of the API. For more information, see Unicode in the Windows API. They use data types that enable you to build both 32- and 64-bit versions of your application from a single source code base. For more information, see Getting Ready for 64-bit Windows. Additional features include Header Annotations and STRICT Type Checking.

Visual C++ and the Windows Header Files

Microsoft Visual C++ includes copies of the Windows header files that were current at the time Visual C++ was released. Therefore, if you install updated header files from an SDK, you may end up with multiple versions of the Windows header files on your computer. If you do not ensure that you are using the latest version of the SDK header files, you will receive the following error code when compiling code that uses features that were introduced after Visual C++ was released: error C2065: undeclared identifier.

Macros for Conditional Declarations

Certain functions that depend on a particular version of Windows are declared using conditional code. This enables you to use the compiler to detect whether your application uses functions that are not supported on its target version(s) of Windows. To compile an application that uses these functions, you must define the appropriate macros. Otherwise, you will receive the C2065 error message.

Читайте также:  Андроид лаунчер для windows phone

The Windows header files use macros to indicate which versions of Windows support many programming elements. Therefore, you must define these macros to use new functionality introduced in each major operating system release. (Individual header files may use different macros; therefore, if compilation problems occur, check the header file that contains the definition for conditional definitions.) For more information, see SdkDdkVer.h.

The following table describes the preferred macros used in the Windows header files. If you define NTDDI_VERSION, you must also define _WIN32_WINNT.

Minimum system required Value for NTDDI_VERSION
Windows 10 1903 «19H1» NTDDI_WIN10_19H1 (0x0A000007)
Windows 10 1809 «Redstone 5» NTDDI_WIN10_RS5 (0x0A000006)
Windows 10 1803 «Redstone 4» NTDDI_WIN10_RS4 (0x0A000005)
Windows 10 1709 «Redstone 3» NTDDI_WIN10_RS3 (0x0A000004)
Windows 10 1703 «Redstone 2» NTDDI_WIN10_RS2 (0x0A000003)
Windows 10 1607 «Redstone 1» NTDDI_WIN10_RS1 (0x0A000002)
Windows 10 1511 «Threshold 2» NTDDI_WIN10_TH2 (0x0A000001)
Windows 10 1507 «Threshold» NTDDI_WIN10 (0x0A000000)
WindowsВ 8.1 NTDDI_WINBLUE (0x06030000)
WindowsВ 8 NTDDI_WIN8 (0x06020000)
WindowsВ 7 NTDDI_WIN7 (0x06010000)
Windows ServerВ 2008 NTDDI_WS08 (0x06000100)
WindowsВ Vista with Service PackВ 1 (SP1) NTDDI_VISTASP1 (0x06000100)
WindowsВ Vista NTDDI_VISTA (0x06000000)
Windows ServerВ 2003 with Service PackВ 2 (SP2) NTDDI_WS03SP2 (0x05020200)
Windows ServerВ 2003 with Service PackВ 1 (SP1) NTDDI_WS03SP1 (0x05020100)
Windows ServerВ 2003 NTDDI_WS03 (0x05020000)
WindowsВ XP with Service PackВ 3 (SP3) NTDDI_WINXPSP3 (0x05010300)
WindowsВ XP with Service PackВ 2 (SP2) NTDDI_WINXPSP2 (0x05010200)
WindowsВ XP with Service PackВ 1 (SP1) NTDDI_WINXPSP1 (0x05010100)
WindowsВ XP NTDDI_WINXP (0x05010000)

The following tables describe other macros used in the Windows header files.

Minimum system required Minimum value for _WIN32_WINNT and WINVER
WindowsВ 10 _WIN32_WINNT_WIN10 (0x0A00)
WindowsВ 8.1 _WIN32_WINNT_WINBLUE (0x0603)
WindowsВ 8 _WIN32_WINNT_WIN8 (0x0602)
WindowsВ 7 _WIN32_WINNT_WIN7 (0x0601)
Windows ServerВ 2008 _WIN32_WINNT_WS08 (0x0600)
WindowsВ Vista _WIN32_WINNT_VISTA (0x0600)
Windows ServerВ 2003 with SP1, WindowsВ XP with SP2 _WIN32_WINNT_WS03 (0x0502)
Windows ServerВ 2003, WindowsВ XP _WIN32_WINNT_WINXP (0x0501)
Minimum version required Minimum value of _WIN32_IE
Internet Explorer 11.0 _WIN32_IE_IE110 (0x0A00)
Internet Explorer 10.0 _WIN32_IE_IE100 (0x0A00)
Internet Explorer 9.0 _WIN32_IE_IE90 (0x0900)
Internet Explorer 8.0 _WIN32_IE_IE80 (0x0800)
Internet Explorer 7.0 _WIN32_IE_IE70 (0x0700)
Internet Explorer 6.0 SP2 _WIN32_IE_IE60SP2 (0x0603)
Internet Explorer 6.0 SP1 _WIN32_IE_IE60SP1 (0x0601)
Internet Explorer 6.0 _WIN32_IE_IE60 (0x0600)
Internet Explorer 5.5 _WIN32_IE_IE55 (0x0550)
Internet Explorer 5.01 _WIN32_IE_IE501 (0x0501)
Internet Explorer 5.0, 5.0a, 5.0b _WIN32_IE_IE50 (0x0500)

Setting WINVER or _WIN32_WINNT

You can define these symbols by using the #define statement in each source file, or by specifying the /D compiler option supported by Visual C++.

For example, to set WINVER in your source file, use the following statement:

#define WINVER 0x0502

To set _WIN32_WINNT in your source file, use the following statement:

#define _WIN32_WINNT 0x0502

To set _WIN32_WINNT using the /D compiler option, use the following command:

cl -c /D_WIN32_WINNT=0x0502 source.cpp

For information on using the /D compiler option, see /D (preprocessor definitions).

Note that some features introduced in the latest version of Windows may be added to a service pack for a previous version of Windows. Therefore, to target a service pack, you may need to define _WIN32_WINNT with the value for the next major operating system release. For example, the GetDllDirectory function was introduced in Windows ServerВ 2003 and is conditionally defined if _WIN32_WINNT is 0x0502 or greater. This function was also added to WindowsВ XP with SP1. Therefore, if you were to define _WIN32_WINNT as 0x0501 to target WindowsВ XP, you would miss features that are defined in WindowsВ XP with SP1.

Controlling Structure Packing

Projects should be compiled to use the default structure packing, which is currently 8 bytes because the largest integral type is 8 bytes. Doing so ensures that all structure types within the header files are compiled into the application with the same alignment the Windows API expects. It also ensures that structures with 8-byte values are properly aligned and will not cause alignment faults on processors that enforce data alignment.

Faster Builds with Smaller Header Files

You can reduce the size of the Windows header files by excluding some of the less common API declarations as follows:

Define WIN32_LEAN_AND_MEAN to exclude APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets.

Оцените статью