31

Related questions
How can I detect the operating system in C/C++?

How can I find out what operating system I am running under in GCC or in ANSI C?

I'd be fine If I can know if I'm running on POSIX.


UPDATE:

It doesn't make a difference to me whether it is at compile time or run time. I'm using this in a debug routine, so performance isn't that important.

I'm looking for the path separator. Windows & Unix/Linux/BSD would be fine.

And, I'm trying to find the basename on a path. I found some solutions, but the solutions include a lot of includes which I do not want. I'm going to mod up this solution.


I'm on Mac OS X 10.4.11, and following this URL, I executed and got the following output:

mac $ touch myfile.c
mac $ gcc -std=c99 -E -dM myfile.c
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __GNUC_PATCHLEVEL__ 1
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L
#define __APPLE_CC__ 5367
#define __UINTMAX_TYPE__ long long unsigned int
#define __LDBL_MAX_EXP__ 1024
#define __SCHAR_MAX__ 127
#define __USER_LABEL_PREFIX__ _
#define __STDC_HOSTED__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __DBL_DIG__ 15
#define __FLT_EPSILON__ 1.19209290e-7F
#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L
#define __ppc__ 1
#define __strong 
#define __APPLE__ 1
#define __DECIMAL_DIG__ 33
#define __LDBL_HAS_QUIET_NAN__ 1
#define __DYNAMIC__ 1
#define __GNUC__ 4
#define __DBL_MAX__ 1.7976931348623157e+308
#define __DBL_HAS_INFINITY__ 1
#define __STRICT_ANSI__ 1
#define __weak 
#define __DBL_MAX_EXP__ 1024
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __GXX_ABI_VERSION 1002
#define __FLT_MIN_EXP__ (-125)
#define __DBL_MIN__ 2.2250738585072014e-308
#define __DBL_HAS_QUIET_NAN__ 1
#define __REGISTER_PREFIX__ 
#define __NO_INLINE__ 1
#define _ARCH_PPC 1
#define __FLT_MANT_DIG__ 24
#define __VERSION__ "4.0.1 (Apple Computer, Inc. build 5367)"
#define __BIG_ENDIAN__ 1
#define __SIZE_TYPE__ long unsigned int
#define __FLT_RADIX__ 2
#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L
#define __NATURAL_ALIGNMENT__ 1
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 2147483647L
#define __FLT_HAS_INFINITY__ 1
#define __STDC_VERSION__ 199901L
#define _BIG_ENDIAN 1
#define __LDBL_MANT_DIG__ 106
#define __WCHAR_TYPE__ int
#define __FLT_DIG__ 6
#define __INT_MAX__ 2147483647
#define __LONG_DOUBLE_128__ 1
#define __FLT_MAX_EXP__ 128
#define __DBL_MANT_DIG__ 53
#define __WINT_TYPE__ int
#define __LDBL_MIN_EXP__ (-968)
#define __MACH__ 1
#define __LDBL_MAX_10_EXP__ 308
#define __DBL_EPSILON__ 2.2204460492503131e-16
#define __INTMAX_MAX__ 9223372036854775807LL
#define __FLT_DENORM_MIN__ 1.40129846e-45F
#define __PIC__ 1
#define __FLT_MAX__ 3.40282347e+38F
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long long int
#define __GNUC_MINOR__ 0
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L
#define __PTRDIFF_TYPE__ int
#define __LDBL_MIN_10_EXP__ (-291)
#define __LDBL_DIG__ 31
#define __POWERPC__ 1
mac $
Community
  • 1
  • 1
historystamp
  • 1,418
  • 4
  • 14
  • 24
  • 1
    More, the existing is about detecting at compiler time, which this one seems to be about detection at runtime. Sorry for the misplaced close vote. Re-open vote issued. – dmckee --- ex-moderator kitten Jul 05 '12 at 19:14
  • Reopened the question :) –  Jul 05 '12 at 19:18
  • Do you want to determine that at runtime or compile time? – netcoder Jul 05 '12 at 19:27
  • 2
    But what would you do with this information? If your program has no OS dependencies it would not matter, and if it has OS dependencies you have already compiled it with the appropriate headers so you already know. (?) – src Jul 05 '12 at 19:31
  • So when you say "running under in GCC", do you mean whether the `-std=gnuxx` flag is enabled or whether the compiler is GCC? – someguy Jul 05 '12 at 19:59
  • This question is somehwat badly phrased - to verify wether a system is POSIX (compliant) you'd have to check every bit of functionality against the standard. The presence of headers or preprocessor symbols say neither about whether a system "is POSIX", or even whether the system claims to be POSIX-compliant (the POSIX standard does not mandate anything about non-POSIX systems). – Remember Monica Sep 05 '22 at 00:06

5 Answers5

41

The Single UNIX Specification requires the existence of unistd.h, which can tell you the POSIX version (via the _POSIX_VERSION macro).

But how can you include unistd.h if you don't know yet that you are in fact compiling on a UNIX?

That is where this GCC document comes handy. According to it, testing for the presence, or evaluation-to-true of __unix__ should tell you that the system is a UNIX. So:

#ifdef __unix__
/* Yes it is a UNIX because __unix__ is defined.  */

#include <unistd.h>

/* You can find out the version with _POSIX_VERSION.
..
..  */

#endif

__unix__ is not defined on Mac OS X, so to account for that, you could instead do:

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))

To get a list of system specific predefined macros on your system, you may execute:

cpp -dM /dev/null

For example, my GNU/Linux system also additionally defines __linux__ and __gnu_linux__ apart from __unix__ and a bunch of other stuff.


Another useful document that you must look at is this Wiki.

It goes on to present a way of detecting the presence and version of POSIX in a way similar to the one I described above.


EDIT: Since you really want to do all this because you want to decide which directory separator to use, look at this URL. It says:

Note File I/O functions in the Windows API convert "/" to "\" as part of converting the name to an NT-style name, except when using the "\?\" prefix as detailed in the following sections.

I don't program on Windows, or know much anything about it, so I can't say I've banked on this.

ArjunShankar
  • 23,020
  • 5
  • 61
  • 83
  • 4
    Well you know that UNIX is (mostly) POSIX, but it doesn't mean non-UNIX is not POSIX though. – netcoder Jul 05 '12 at 19:27
  • 8
    `unistd.h` defines the `_POSIX_*` macros. UNIX is POSIX, so there's a `unistd.h` for sure. My point was that you could have a POSIX compliant system that is not UNIX, where `__unix__` wouldn't be defined (speculations really). In short, POSIX is not UNIX. ;-) – netcoder Jul 05 '12 at 19:32
  • @netcoder - I went about it in the reverse way. I wanted to be sure `unistd.h` is *there at all* before I can include it and see the POSIX version. Eventually, the only 'safe' way I could see was to look for `__unix__`. But you are right (POSIX != UNIX), I wouldn't say it's bullet proof. – ArjunShankar Jul 05 '12 at 19:35
  • @netcoder - I did some more digging. Some people on the internets seem to agree with the way I include `unistd.h` (see edit). Thanks for the nudge. – ArjunShankar Jul 05 '12 at 19:57
  • Is there actually another way to check whether `unistd.h` can be included? – someguy Jul 05 '12 at 20:04
  • 2
    @someguy: See [Can the C preprocessor be used to tell if a file exists?](http://stackoverflow.com/questions/142877/can-the-c-preprocessor-be-used-to-tell-if-a-file-exists) – netcoder Jul 05 '12 at 20:10
  • this GCC document -- Now, you have to run around and check on each system you plan on using to figure out what __ are available. I have a solution. Thanks. – historystamp Jul 05 '12 at 23:00
  • I made a final edit, handling the case of Mac OS X (POSIX compliant, but does not define `__unix__`), and a short note on path separators. – ArjunShankar Jul 06 '12 at 11:14
  • 1
    'Windows API convert "/" to "\"' -- Thanks for this comment. I was wondering why the windows code for finding the basename included both "/" & "\". Works out well, look for unix & if you miss a Unix, it will not be too bad. [ Just glancing at the article you reference on microsoft.com is reason enough for me to avoid Windows. ] – historystamp Jul 06 '12 at 16:56
7

It is possible to solve your problem using autoconf tool to discover the presence of unistd.h and then would add a #define HAVE_UNISTD_H 1 line in a generated config.h if unistd.h was found, but I find that autoconf is a little hard to use, and is very out-dated.

If by any chance you are using cmake, you can solve it the same way. You could create a config.h.in containing something like this:

#ifndef CONFIG_H
#define CONFIG_H

#cmakedefine HAVE_UNISTD_H 1

#endif

And your project's CMakeLists.txt would look like this:

project(MyApp)

include(CheckIncludeFiles)
check_include_file("unistd.h" HAVE_UNISTD_H)

configure_file(config.h.in config.h @ONLY)

add_executable(${PROJECT_NAME} main.c)

and then to generate from the command line:

cmake . -G"Unix Makefiles"

or generate Xcode project (OSX only):

cmake . -G"Xcode"

or generate a visual studio 2013 solution project (Windows only):

cmake . -G"Visual Studio 12 2013 Win64"

cmake generators = epic win

If your operating system is POSIX, then your generated config.h should look like this:

#ifndef CONFIG_H
#define CONFIG_H

#define HAVE_UNISTD_H 1

#endif

Otherwise, it will look like that:

#ifndef CONFIG_H
#define CONFIG_H

/* #undef HAVE_UNISTD_H */

#endif

And then you are free to your your trusted generated config.h :

#include "config.h"

#if HAVE_UNISTD_H
#   include <unistd.h>
#endif

int main (int argc, const char * argv[])
{
#if defined(_POSIX_VERSION)
     /* POSIX code here */
#else
     /* non-POSIX code here */
#endif
    return 0;
}
mchiasson
  • 2,452
  • 25
  • 27
  • I'd just like to point out that this process is even less convoluted due to the update to the CheckIncludeFiles macro in CMake 3.3. The new syntax is as follows: `CHECK_INCLUDE_FILE( [])` is an optional parameter to the function and is dedicated to adding compiler flags, thus eliminating the need for "config.h.in" So my line in CMakeLists.txt looks something like `check_include_file("unistd.h" HAVE_UNISTD_H)` – NullPointerException Nov 11 '20 at 04:40
  • @NullPointerException my example is also using CheckIncludeFiles as well. I'm using it exactly like how you suggest to populate `HAVE_UNISTD_H` exactly how you did it. You can chose to generate a header with it, or pass it as a compile flag, it's entirely up to you. I prefer the generated header way because my IDE grays out the false preprocessor parts correctly that way. – mchiasson Dec 07 '20 at 22:32
5

I know this is kind of a dead question, but I had to add this.

In C++17 (and C as a GCC and clang extension), there is now a __has_include operator that can be used in #if directives. This means that you can check for posix compliance like this:

#if __has_include(<unistd.h>)
    // System is posix-compliant
#else
    // System is not posix-compliant
#endif
mediocrevegetable1
  • 4,086
  • 1
  • 11
  • 33
Lysander Mealy
  • 113
  • 1
  • 6
1

Here is what I ended up with:

#include <stdio.h>
/*
NAME
    basename -- return pointer to last component of a pathname

Distribution: This function is in the public domain. 

Origin of function:
http://www.koders.com/c/fidEB79B7607A210C3BB7B813E793465F9D469AE912.aspx


SYNOPSIS
    char *basename (const char *name)

DESCRIPTION
    Given a pointer to a string containing a typical pathname
    (/usr/src/cmd/ls/ls.c for example), returns a pointer to the
    last component of the pathname ("ls.c" in this case).

Restrictions:
    Presumes a UNIX or DOS/Windows style path with UNIX or DOS/Windows 
    style separators.
*/

/*
NAME:
    basename: 

Function:
    return pointer to last component of a pathname

Distribution: 
    This function is in the public domain. 

Origin of function:
    http://www.koders.com/c/fidEB79B7607A210C3BB7B813E793465F9D469AE912.aspx


SYNOPSIS:
    char *basename (const char *name)

DESCRIPTION:
    Given a pointer to a string containing a typical pathname
    (/usr/src/cmd/ls/ls.c for example), returns a pointer to the
    last component of the pathname ("ls.c" in this case).

Restrictions:
    Presumes a UNIX or DOS/Windows style path with UNIX or
    DOS/Windows style separators.
    Windows volumes are only a-zA-Z.
    The original code suggests ISALPHA.

*/

char * basename (const char *name)
{
const char *base;
// predefined OS symbols
// http://sourceforge.net/apps/mediawiki/predef/index.php?title=Operating_Systems#UNIX_Environment

#ifndef DIR_SEPARATOR
#  define DIR_SEPARATOR '/'
#endif

#ifndef DIR_SEPARATOR_2 
#  define DIR_SEPARATOR_2 '\\'
#endif

// Check if we are running Unix like os
//   else assume Windows.  Note if we guess wrong, it's not
//   so bad because Windows includes the Unix separator.
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#  define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
#else
#  define IS_DIR_SEPARATOR(ch) \
(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
/* Skip over the disk name in MSDOS pathnames. */
if (isalpha(name[0]) && name[1] == ':') 
    name += 2;
#endif


for (base = name; *name; name++)
    {
    if (IS_DIR_SEPARATOR (*name))
        {
        base = name + 1;
        }
    }
return (char *) base;
}




int main (int argc, const char * argv[]) {
    /* Return the basename of a pathname. */


#define S1 "/usr/src/cmd/ls/ls.c"
#define S2 "/usr/src/cmd/ls/abc"
#define S3 "a:/usr/src/cmd/ls/def"
#define S4 "ghi"
#define S5 "jkl.txt"
#define S6 "d:\\usr\\src\\cmd\\mno.txt"
#define S7 "d:pqm.txt"

printf(S1 "  \t is %s\n",basename(S1));
printf(S2 "  \t is %s\n",basename(S2));
printf(S3 "  \t is %s\n",basename(S3));
printf(S4 "  \t is %s\n",basename(S4));
printf(S5 "  \t is %s\n",basename(S5));
printf(S6 "  \t is %s\n",basename(S6));
printf(S7 "  \t is %s\n",basename(S7));
    return 0;

}

historystamp
  • 1,418
  • 4
  • 14
  • 24
0

Inspired by @ArjunShankar, include unistd.h and test macro _POSIX_VERSION.

#include <unistd.h>
#include <stdio.h>

int main()
{
    #ifdef _POSIX_VERSION
    printf("_POSIX_VERSION:%ld\n", _POSIX_VERSION);
    #else
    printf("Not support posix.\n");
    #endif
    return 0;
}

On my Ubuntu, it prints out:

_POSIX_VERSION:200809
Hogan Chou
  • 11
  • 2