25

For example, C11 dictates that size_t should be declared in the following header files:

  • stddef.h
  • stdio.h
  • stdlib.h
  • string.h
  • time.h
  • uchar.h
  • wchar.h

When reading C11, I found there are many other data types declared in more than one standard header files.

Questions

  1. Let's say in the case of size_t. Why not just in stddef.h for simplicity?
  2. Let's say a C compiler implements size_t in those header files. Are they guaranteed to have the same definition in those header files?
dandan78
  • 13,328
  • 13
  • 64
  • 78
Astaroth
  • 2,241
  • 18
  • 35
  • 2
    size_t was introduced in c89 / c90 / K&R2. It was already too late to realise that it was in fact a basic type (internal to the language and compiler) Most headers. need it, and the headers that need it supply a definition for it – joop Aug 15 '14 at 12:25

4 Answers4

23

As an example of a function declared in stdio.h that requires size_t be predeclared, consider snprintf(). As it is, if you want to use it in your code, all you need to do is #include <stdio.h>. If size_t were declared only in stddef.h, you would have to

#include <stddef.h>
#include <stdio.h>

Not only that, but since stdio.h declares snprintf whether you use it or not, you would have to include both files every time you needed anything in stdio.h to avoid compiler errors; stdio.h would have an artificial dependency on stddef.h. That causes your source code to become longer and more brittle (notice that if you reverse the order of the two directives it would also break). Instead, we write header files so that they stand alone and do not depend on other headers, and this is what the C standardization committee decided on for the standard library.

trent
  • 25,033
  • 7
  • 51
  • 90
  • 3
    This is believable and seems logical at first glance, but really isn't. `size_t` is a typedef for a specific predefined type, and system headers are system-specific. On a system where `size_t` is a typedef for e.g. `unsigned int`, there would be no problem (no difficulty and no conformance issue) if the implementation declares `snprintf` as taking `unsigned int` instead of `size_t`, so that the typedef isn't needed. –  Aug 15 '14 at 23:39
  • @trentcl, What's wrong with interdependency among header files? In fact, in C standard header files of GCC, I saw many dependencies among them when particular compiler directives are set. For your statement that header files are written in a way that each of them are independent, could you give me a reference for it? – Astaroth Aug 16 '14 at 14:06
  • @hvd: Standard header files need not be written in C or even exist at all, but usually they do exist and are written in C. As Klas observed earlier, it's often possible to change size_t to be a different size by setting a compiler option -- how would you write stdio.h then? The standard is written the way it is because of the reasons I gave. What it *permits* is another thing altogether. – trent Aug 17 '14 at 11:03
  • 1
    @Astaroth, what's wrong with header file dependencies is that it makes code longer and more brittle to no advantage. Your proposal, if I implemented it like most implementations do, would demand some definition of size_t, *in the client code*, before every `#include `. That's redundant, and it breaks (practically all) pre-C99 C where that wasn't necessary. So it's best to make sure header files provide all the information necessary to use the things in them. I don't know which "particular compiler directives" you're referring to; could you give an example? – trent Aug 17 '14 at 11:15
  • @trentcl, +1 for your statement "it breaks (practically all) pre-C99 C", but for the rendundancy, `stdio.h` could include `stddef.h`, couldn't it? BTW, I've been using GCC 4.8 of MinGW with Code::Block as its IDE. I've tried to use `snprintf()` in a simple code with only `stdio.h` is included, and GCC compiles it finely. In `stdio.h` of my GCC, there is `#include ` under `#ifndef RC_INVOKED` – Astaroth Aug 17 '14 at 12:13
  • @trentcl "As Klas observed earlier, it's often possible to change size_t to be a different size by setting a compiler option -- how would you write stdio.h then?" In the case of gcc's `-m32`/`-m64` options for x86, by using `__SIZE_TYPE__`. Which is exactly what gcc's own `stddef.h` does anyway. As for "the standard is written the way it is": the C99 rationale doesn't say so. It merely says the types are defined in multiple headers where they're also referenced, not that that's because they need to be. It's just because it's useful, in part useful for the implementer, but also for the user. –  Aug 17 '14 at 21:43
  • @hvd "It merely says the types are defined in multiple headers where they're also referenced, not that that's because they need to be" -- isn't that what I just said? – trent Aug 17 '14 at 23:28
  • @Astaroth, yes, one way of resolving that dependency is for `stdio.h` to include another header file that defines `size_t`. In fact, that's how I would normally expect it to be resolved. The way you avoid brittleness is by making sure this is done in the header itself and not by the code that uses it. – trent Aug 17 '14 at 23:34
  • @trentcl No, it's not. You *are* saying they're defined in multiple headers where they're referenced because they need to be. That last part is not in the C99 rationale, and I'm not seeing any source for that claim. –  Aug 18 '14 at 05:45
  • The things that I can't think of is why C standard authors thought such a duplicate definitions in multiple headers should be dictated in the standard. What are the advantages of saying it in the standard? It is easy for C compiler developers to just include the headers that contain the required type definitions, and this will not break the compatibility with older C codes that assumed the particular types (e.g. `size_t`) were surely defined in some headers (e.g. `stdio.h`). – Astaroth Aug 18 '14 at 13:28
  • @Astaroth: I'm not sure what you mean. The standard doesn't determine what a header file contains, only what must happen when you `#include` it -- which is not the same thing. It's perfectly fine for an implementation to define `size_t` in only one file and have each of the headers you listed include it in turn; a conforming implementation could do that. – trent Aug 19 '14 at 22:58
  • In C11 Chapter 7.19, it was said that `size_t` should be declared in ``. Chapter 7.21.1 also says the same thing but for ``. Chapter 7.22 also says the same thing but for ``. Chapter 7.27.1 says the same thing but for ``. Chapter 7.28 says the same thing but for ``. And so on. – Astaroth Aug 20 '14 at 06:21
10

Let's say in case of size_t. Why not just in stddef.h for simplicity?

The type is used in the declaration of functions in all those files. If it wasn't declared in <stdio.h> you would get a compilation error unless you first include <stddef.h>.

Let's say a C compiler implements size_t in those header files. Are they guaranteed to have the same definition in those header files?

Yes, they will have the same definition. Usually, the value is defined in a single place in a separate include file that is included by the others.

In some cases it may be possible to modify the definition with compiler options or defines, for example a compiler that allows 32/64 bit compilation may define size_t as a 32 or 64 bit unsigned entity depending on the target defined on the compiler command line.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
6

There's a subtle difference between by and in - an implementation is completely free to define size_t in a single header, as long as it's defined when the specified headers are included. So, you have two options for that:

  1. Define size_t in every single one and wrap each one in include guards
  2. Define it in a single file, and wrap it in include guards

And yes, size_t must be defined as specified, which is (glibc):

typedef unsigned long size_t;

or

typedef unsigned int size_t

They don't say you have to be sane, they just say it needs to be defined at the time anyone includes one of those headers, because they depend on it being defined and can be used independently. Put simply, if you define something dependent upon size_t, then size_t must first (previously) be defined.

How (or rather, where) you do it is up to your implementation.

Tim Post
  • 33,371
  • 15
  • 110
  • 174
  • 2
    `size_t` is not guaranteed to be the same as `unsigned long`. And isn't on LLP64 implementations. – dan04 Aug 15 '14 at 12:59
  • I'm new to C. I just thought what if a C compiler declares `size_t` in a less popular header? Let's say it is declared only in `wchar.h`, that certainly make us have to do a trial and error in finding where `size_t` is declared, or even worse, we need a grep-like tool just for a trivial thing. For C compiler developers, didn't declared it in a single header means easier maintenance, since there are many types other than `size_t` that also in a situation I just mentioned? I'm eager to know because I didn't see this in Delphi and Java. – Astaroth Aug 15 '14 at 14:07
5

First of all, when one does a #include <stdio.h> there is no requirement that there actually exist a file anywhere called stdio.h, or that the compiler do anything with such a file. Rather, the requirement is that such a line must cause all identifiers which are specified as being associated with <stdio.h> to be defined according to specification. It would be perfectly legitimate for a compiler that saw #include <stdio.h> simply enable the use of certain identifiers that were hard-wired into the compiler. Because the easiest way for compiler vendors to make things behave as the spec requires is to have #include <stdio.h> directives run the text of some file stdio.h through the preprocessor, that's what many compilers do, but that's not required.

When the spec lists "files" where size_t should be declared, what it's really saying is that an #include directive that names any one of those files should create that identifier in global scope. That could be done by having files with all the listed names incorporate a definition of size_t, or by having size_t be built into the compiler but only enabling the built-in definition of the compiler sees a #include directive with one of the indicated names.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 1
    Is there any compiler that does not implement stdio.h as a file? – Be Kind To New Users Aug 16 '14 at 03:11
  • I don't recall having actually worked with any, but such a design could offer three benefits: (1) while all "normal" file systems today allow file names ending in ".h", that has not always been the case; (2) having much of the standard-header data within the compiler could improve performance when using floppies; (3) a compiler could map names to different files, based upon option switches (I think I have seen that done). Also, btw, the standard would allow a compiler to implement `#pragma once`-style functionality implicitly with angle-bracket include-file names. – supercat Aug 16 '14 at 17:46