Dealing with different prototypes of pipe()

According to this manpage, pipe() can have different prototypes depending on the architecture. If I want to be as cross-platform as possible, do I now have to write code that compiles when it is given either prototype? Is this reasonable (or even possible¹)? Alternatively, can I check for the architecture using preprocessor directives?

On the topic of being cross-platform, POSIX only mentions the first prototype, but the Linux manpage does not highlight the second one as non-POSIX-compliant. Is this an error?

¹ I have been trying to make something work using C++20 features, but no success yet.

Asked By: Ground

||

If I want to be as cross-platform as possible, do I now have to write code that compiles when it is given either prototype?

No, there’s no need here.

You’re looking at the section 2 manpage entry, for direct system calls. That’s the docs your language runtime implementors will be imbibing until it suffuses their existence and informs their idle thoughts.

You want the section 3 docs, the C-family runtime. man 3 pipe works as a google search for me, and as a command. That’s the prototype you’re linking against if you’re using any C-family language, how exactly your toolchain arranges to have that portable section 3 api invoke the system-specific section 2 api you found the docs for is … I suspect you need to pull the source for whatever runtime you’re linking against, libc++ or libstdc++ or glibc, dunno and don’t care, for portable code the section 3 API is supposed to Just Work™.

Answered By: jthill

The pipe man page you found has two different purposes:

  1. It documents the system call interface used by the Linux kernel.
  2. It documents the system call wrappers provided by the GNU C library on Linux.

The former can vary from one architecture to another; this is what is happening here. The wrapper provided by the GNU C library however implements the POSIX pipe API:

#include <unistd.h>

int pipe(int fildes[2]);

There’s no ambiguity when compiling or linking a program using pipe, even on an architecture such as Alpha where the system call API is different: the system call API doesn’t appear as such in either the system’s header files or in the system libraries (even though the man page does seem to suggest that it does). On an Alpha Linux system, the GNU C library declares pipe as follows, same as other Linux architectures:

/* Create a one-way communication channel (pipe).
   If successful, two file descriptors are stored in PIPEDES;
   bytes written on PIPEDES[1] can be read from PIPEDES[0].
   Returns 0 if successful, -1 if not.  */
extern int pipe (int __pipedes[2]) __THROW __wur;

Thus on an Alpha, if you write a program assuming the struct fd_pair pipe(void); variant, it will fail to build.

To access the system calls themselves, you’d have to use the syscall function provided by the GNU C library or code the system call yourself. That’s when you’d have to provide architecture-specific code; but very few people need to actually care about this.

Unfortunately on Linux systems the man pages can end up being confusing in this way, because the C library itself doesn’t provide any; so function calls which wrap system calls end up being documented by the system call man page. If you don’t care about the system calls themselves (and most developers don’t, in practice), you’re better off reading the GNU C library’s documentation if you’re programming in C using that library, or the documentation of the runtime library you’re using if it’s not that.

Answered By: Stephen Kitt
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.