2

I was studying up on ncurses.h because I am trying to learn a bit of design aspects for c, and stumbled across a statement saying that stdio.h is inside of ncurses

  #include <ncurses.h>        /*ncurses.h includes stdio.h*/

Is this true? If so, can someone explain to me why, and if that means I don't have to ever include it again?

Also, does this cause any issues because I am not exactly defining it in a regular sense

Ryan Keough
  • 121
  • 1
  • 8
  • This is related (though not a duplicate): https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h – Yunnosch Feb 19 '20 at 01:27

4 Answers4

6

Yes, including <ncurses.h> will almost certainly include <stdio.h>. But I advise not taking advantage of this.

The documentation for ncurses does say:

NOTES
The header file <curses.h> automatically includes the header files <stdio.h> and <unctrl.h>.

(ncurses.h is (usually?) a symbolic link to curses.h.)

Thomas Dickey, the primary maintainer of ncurses, tells us that this goes back to 1994, so you're extremely unlikely to encounter an ncurses implementation that doesn't do this.

The X/Open Curses standard, which ncurses supports, says (emphasis added):

The inclusion of <curses.h> may make visible all symbols from the headers <stdio.h>, <term.h>, <termios.h>, and <wchar.h>.

Furthermore, some functions defined in <ncurses.h> and/or <curses.h> take arguments of type FILE, which is defined in <stdio.h>. (It's conceivable that something could use the FILE type without including <stdio.h>, but that would be contrived and silly, and the possibility is not worth worrying about.)

So #include <ncurses.h> is practically guaranteed to include <stdio.h>.

Having said all that, I advise against taking advantage of this guarantee. If your C source file depends on things declared in <stdio.h>, as a matter of style you should have an explicit #include <stdio.h>, even though it's strictly redundant. More generally, a C source file should have a #include directive for any header that it depends on. This is a matter of style and maintainability, not an absolute requirement. See, for example, this question. The C standard guarantees that including <stdio.h> more than once will not cause problems.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • I'll second this. Even though it's not strictly necessary, you should explicitly include `#include ` so that any developer reading your code can see immediately what is included. – ajxs Feb 19 '20 at 00:04
  • An include guard might be advisable as well. – EvilTeach Feb 19 '20 at 00:06
  • @EvilTeach Both `` and `` already have include guards. – Keith Thompson Feb 19 '20 at 00:07
  • 3
    I couldn't agree more that code that depends on any header should include that header -- where by "code" I mean "C source file", regardless of role or filename extension. – John Bollinger Feb 19 '20 at 00:15
  • 1
    No, @Yunnosch, I intentionally *include* .h files. "Regardless of role or filename extension" is meant to convey this, among other things. For example, if I have a header that declares a function accepting a `FILE *` parameter then I will ensure that that header includes `stdio.h`. – John Bollinger Feb 19 '20 at 00:28
  • @JohnBollinger I somehow managed to read a ".C" into your comment which I now realise is not there.... – Yunnosch Feb 19 '20 at 00:35
  • It's "universally true", of anything that's compatible with X/Open Curses. – Thomas Dickey Feb 19 '20 at 09:51
  • @ThomasDickey I just downloaded a copy of `c094.pdf` from opengroup.org. It says (emphasis added): "The inclusion of `` **may** make visible all symbols from the headers ``, ``, ``, and ``." – Keith Thompson Feb 19 '20 at 18:07
  • That's a start. Next, apply your *reading comprehension* to what's said. `newterm` uses **`FILE`**, for instance, so `` will always be included (otherwise the documentation on TOG is invalid). `` **may** declare a conflicting symbol (unlikely, but to see that, you have to read the *documentation*). – Thomas Dickey Feb 19 '20 at 22:06
  • @ThomasDickey Is there some reason you feel the need to be insulting? (I think you meant `` in your comment, BTW.) Why does the documentation say it "may" make `` symbols visible if, as you correctly point out, `newterm`'s use of `FILE` implies that it must do so? (I can imagine some highly contrived way that it could make `FILE` visible without exposing ``, but that's not realistic.) – Keith Thompson Feb 19 '20 at 23:08
  • 1
    Rather than amend your disparaging comments about ncurses, you want to carry on a conversation. I should ask why. – Thomas Dickey Feb 20 '20 at 00:02
  • 1
    @ThomasDickey: I seriously have no idea what comments of mine you consider to be disparaging. Please enlighten me. – Keith Thompson Feb 20 '20 at 00:25
  • I'd start by deleting the first half of your answer, and refrain from speculating on things that you can't find in documentation. The includes in ncurses have been as you see them for quite a while. – Thomas Dickey Feb 20 '20 at 00:28
  • Nothing I've written was meant to be disparaging. I might clean up the answer later. Since you haven't been specific about what you find disparaging, I might guess that you took "And even if it is, I wouldn't." to imply something I didn't mean to imply. I merely meant that even if the ncurses documentation guarantees that `#include ` includes ``, I would still explicitly include `` in my own code if I use any of its declarations. I didn't say or imply that such a guarantee would be unreliable. I'd be interested in seeing your answer if you care to write one. – Keith Thompson Feb 20 '20 at 00:43
  • 1
    @ThomasDickey FYI, I've rewritten my answer. I'm still curious what you found "disparaging" in my original answer. – Keith Thompson Feb 20 '20 at 17:50
0

It does indeed include stdio.h, and yes this does mean that you don't need to include stdio.h again. This works because the compiler will insert the contents of the #include'd header files at the point in your code that the #include directive was placed. This means that not only was ncurses.h included in your code at the location you specified, but stdio.h was already included in that file at the appropriate location prior to it being placed into your code.

Subsequent includes of stdio.h will have no effect on your program due to the use of include guards.

If you're using anything from stdio.h in your own code I would consider it good practice to add the #include <stdio.h> directive to your own source files. My reasoning is that it communicates directly to the next developer reading your code that stdio functionality is used here without relying on implicit information.

ajxs
  • 3,347
  • 2
  • 18
  • 33
0

In general, even if one header includes another as part of its implementation, you should always trust the C standard and the documentation of whatever API you're using. If it says that a certain header file is the one that contains a certain item, or it says that in order to access a certain item, include this header, you should follow that.

  1. It's not harmful to include the same file multiple times if it has include guards (i.e. #pragma once or #ifndef _HEADER_NAME ... #endif)
  2. You're technically relying on an implementation detail if you omit an include that the C standard (or API documentation) says is the correct file to include for a certain declaration or definition. That means that the next version of your compiler or library could very well remove that convenient nested include that makes your program a couple of lines shorter.
Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • 1
    Details notwithstanding, the standard specifies that any of the standard library headers can safely be included multiple times, and that the relative order of different standard library headers is not significant. The same is often true of the headers of third-party libraries, but of course, one cannot make general guarantees about those. – John Bollinger Feb 19 '20 at 00:25
0

ncurses' curses.h includes <stdio.h> because a few of the (X/Open Curses) standard functions which curses.h declares use FILE. The C standard refers to FILE as an "object type", which some might read literally as requiring a typedef. However there have been implementations where FILE is a symbol defined with #define, e.g.,

#define   FILE    struct _iobuf

(quoting from more than one BSD: 4.3BSD, SunOS 4, Ultrix). Without delving into its history, I'd assume the change to make it a typedef came from the AT&T code since it shows up in the SVr4 implementations.

For that reason (as well as it being the simplest way to guarantee that FILE is declared properly), curses.h will include stdio.h.

Now... there are a few other header files which you might encounter which require another header file to be included, to make them useful. One longstanding example is for the stat function, i.e.,

#include <sys/types.h>
#include <sys/stat.h>

but in the relevant (system-specific) documentation, both headers are shown in the manual page summary. The POSIX documentation for stat does not point that out, but uses it in the examples. Some newer implementations include (or provide in some roundabout way) the definitions from <sys/types.h> needed in <sys/stat.h>, but in writing portable code, that has not been something to rely upon.

curses was never documented in that way, e.g., you're unlikely to find manual pages showing

#include <stdio.h>
#include <curses.h>

because the original 4BSD curses included <stdio.h>. Interestingly enough, 4.2BSD curses header did not use any definition from stdio.h. It also included sgtty.h (analogous to termios.h), but used those definitions in the header file. Perhaps the original developer thought that including stdio.h was a good idea. In any case, in later versions of curses, it did use FILE, and since the precedent of including stdio.h. from curses.h was well established, no one considered splitting things up as done with <sys/types.h> and <sys/stat.h>.

ncurses' documentation has mentioned the header files which curses.h includes, in a NOTES section:

The header file <curses.h> automatically includes the header files <stdio.h> and <unctrl.h>.

That note dates back to ncurses 1.8.7 in 1994, making it rather unlikely that you will encounter a version of ncurses for which the statement is untrue.

X/Open Curses has something similar to say:

The inclusion of <curses.h> may make visible all symbols from the headers <stdio.h>, <term.h>, <termios.h> and <wchar.h>.

HPUX curses, for instance, includes <term.h> from <curses.h> to declare setupterm in curses.h, but ncurses (and Solaris curses) do not. AIX curses includes <term.h> and <termios.h>. Again, ncurses (and Solaris curses) do not. X/Open Curses says "may make visible" because including a header file does not necessarily make all symbols in it visible (there are ifdef's to consider).

However, these functions in any X/Open Curses (i.e., anything more current than 1990) use FILE, making <stdio.h> needed for <curses.h>:

Now... including <stdio.h> before <curses.h> probably will not make any difference (aside from adding clutter to your program). It's possible (but unlikely) that there could be some symbol redefined in <curses.h> which alters the behavior of the standard features in <stdio.h>. Since any implementation of stdio.h which you are likely to encounter has include-guards (a feature from the 1990s—not seen in SunOS 4's 1994 headers) including <stdio.h> after <curses.h> would also be unlikely to change the behavior of your program (again, clutter being the only result).

Include-guards have been the preferred style for system headers since the 1990s. I have a script (called Include) which I use for test-compiling headers which I wrote in 1998, to check that a given header includes the necessary headers (such as in this case) to provide all of the necessary typedefs and symbols used in the header file.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105