6

By reading What does -D_XOPEN_SOURCE do/mean? , I understand that how to use feature test macros.

But I still don't understand why do we need it, I mean, can we just enable all features available? Then the doc writes like this: this function only available in Mac/BSD, that function only available in Linux, if you use it, then your program can only be running on that system.

So why do we need a feature test macro in the first place?

scriptboy
  • 777
  • 8
  • 25

3 Answers3

7

why do we need it, I mean, can we just enable all features available?

Imagine some company has written perfectly fine super portable code roughly like the following:

#include <stdlib.h>
struct someone_s { char name[20]; };

/// @brief grants Plant To someone
int grantpt(int plant_no, struct someone_s someone) {
   // some super plant granting algorithm here
   return 0;
}

int main() {
   // some program here
   struct someone_s kamil = { "Kamil" };
   return grantpt(20, kamil);
}

That program is completely fine and all is working fine, and that program is very C compatible, thus should be portable to anywhere. Now imagine for a moment that _XOPEN_SOURCE does not exist! A customer receives sources of that program and tries to compile and run it on his bleeding edge Unix computer with certified C compiler on a certified POSIX system, and he receives an error that that company has to fix, and in turn has to pay for:

/tmp/1.c:7:9: error: conflicting types for ‘grantpt’; have ‘int(struct someone_s,  int)’
    7 |     int grantpt(struct someone_s someone, int plant_no) {
      |         ^~~~~~~
In file included from /tmp/1.c:2:
/usr/include/stdlib.h:977:12: note: previous declaration of ‘grantpt’ with type ‘int(int)’
  977 | extern int grantpt (int __fd) __THROW;
      |            ^~~~~~~

Looks like a completely random name picked for a function is already taken in POSIX - grantpt().

When introducing new symbols that are not in reserved space, standards like POSIX can't just "add them" and expect the world not to protest - conflicting definitions can and will and do break valid programs. To battle the issue feature_test_macros were introduced. When a program does #define _XOPEN_SOURCE 500 it means that it is prepared for the POSIX standard and there are no conflicts between the code and symbols introduced by POSIX in that version.

Feature test macros are not just "my program wants to use these functions", it is most importantly "my program has no conflicts with these functions", which is way more important, so that existing programs continue to run.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • I see, as @zowl's answer said (https://stackoverflow.com/a/68260262/6931919), simply means: "by define this macro test feature, I am sure that my program have no conflict with `_XOPEN_SOURCE 500`". Can I just think "feature test macros" as "namespace" in C++? – scriptboy Jul 06 '21 at 03:20
  • Sorry another question, so in order to use a "special" function, 3 things are necessary: 1) system implementation provide that *function implementation* 2) glibc has a wrapper, but not enable as default 3) I need to define a feature test macro to enable that function definition. Then I can call that function, am I right? (thank you very much) – scriptboy Jul 06 '21 at 03:35
  • 1
    `Can I just think "feature test macros" as "namespace" in C++?` Kind of, but these are different things. `am I right?` yes – KamilCuk Jul 06 '21 at 07:17
3

The theoretical reason why we have feature selection macros in C, is to get the C library out of your way. Suppose, hypothetically, you want to use the name getline for a function in your program. The C standard says you can do that. But some operating systems provide a C library function called getline, as an extension. Its declaration will probably clash with your definition. With feature selection macros, you can, in principle, tell those OSes' stdio.hes not to declare their getline so you can use yours.

In practice these macros are too coarse grained to be useful, and the only ones that get used are the ones that mean "give me everything you got", and people do exactly what you speculate they could do, in the documentation.

Newer programming languages (Ada, C++, Modula-2, etc.) have a concept of "modules" (sometimes also called "namespaces") which allow the programmer to give an exact list of what they want from the runtime library; this works much better.

zwol
  • 135,547
  • 38
  • 252
  • 361
2

Why do we need feature test macros?

You use feature test macros to determine if the implementation supports certain features or if you need to select an alternative way to implement whatever it is you're implementing.

One example is the set of *_s functions, like strcpy_s:
errno_t strcpy_s(char *restrict dest, rsize_t destsz, const char *restrict src);

// put this first to signal that you actually want the LIB_EXT1 functions
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>

Then in your code:

#ifdef __STDC_LIB_EXT1__
    errno_t err = strcpy_s(...);  // The implementation supports it so you can use it
#else
    // Not supported, use an alternative, like your own implementation
    // or let it fail to compile.
#fi

can we just enable all features available?

When it comes to why you need to tell the implementation that you actually want a certain set of features (instead of it just including them all automatically) I have no better answer than that it could possibly make the programs slower to compile and could possibly also make it produce bigger executables than necessary.

Similarly, the implementation does not link with every library it has available, but only the most basic ones. You have to tell it what you need.

In theory, you could create header file which defines all the possible macros that you've found that will enable a certain set of features.

#define _XOPEN_SOURCE     700
#define __STDC_LIB_EXT1__ 1
...

But as you see with _XOPEN_SOURCE, there are different releases, and you can't enable them all at the same time, you need to select one.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • I think this question is about why you need to do `#define __STDC_WANT_LIB_EXT1__ 1`, but your answer only explains why you need to do `#ifdef __STDC_LIB_EXT1__`. – Joseph Sible-Reinstate Monica Jul 05 '21 at 17:25
  • @JosephSible-ReinstateMonica Ah, that's possible. I focused on the "_Why do we need feature test macros?_" part of the question. I'll see what I can do about that other one. – Ted Lyngmo Jul 05 '21 at 17:27
  • @JosephSible-ReinstateMonica I gave it a shot. – Ted Lyngmo Jul 05 '21 at 17:32
  • Sorry, if the glibc has define all the functions with "feature test macros", but I don't include the header file, will it still be linked? (then bigger and slower?) – scriptboy Jul 06 '21 at 03:36
  • 2
    @scriptboy Not necessarily. That's up to the implementation. The best thing would be if you didn't define the macros that tells the implementation that you want to enable the features in the first place. Add defines only for the features you need and include what you need. – Ted Lyngmo Jul 06 '21 at 04:36