I am fairly new to C++. I am currently working on a group project and we want to make our classes compatible with both the lab computers (Windows) and my computer (Mac OS X).
Here is what we have been putting at the top of our files:
#ifdef TARGET_OS_X
# include <GLUT/glut.h>
# include <OpenGL/OpenGL.h>
#elif defined _WIN32 || defined _WIN64
# include <GL\glut.h>
#endif
I realize this question has been asked before but my searches have been giving me conflicting answers such as "_MAC", "TARGET_MAC_OS", "MACINTOSH", etc. What is the current and correct declaration to put in the #ifdef statement to make this compatible with Mac? Right now it is not working.
Thank you!
According to this answer:
#ifdef __APPLE__
#include "TargetConditionals.h"
#ifdef TARGET_OS_IPHONE
// iOS
#elif TARGET_IPHONE_SIMULATOR
// iOS Simulator
#elif TARGET_OS_MAC
// Other kinds of Mac OS
#else
// Unsupported platform
#endif
#endif
So in short:
#ifdef __APPLE__
#include "TargetConditionals.h"
#ifdef TARGET_OS_MAC
#include <GLUT/glut.h>
#include <OpenGL/OpenGL.h>
#endif
#elif defined _WIN32 || defined _WIN64
#include <GL\glut.h>
#endif
It depends on the compiler. #ifdef __APPLE__ works for gcc.
According to Microsoft, _WIN32 will cover both the 32-bit and 64-bit versions of Windows. And __APPLE__ works for Clang (at least in Mavericks). So one correct way to write the ifdefs above is:
#ifdef __APPLE__
DoSomething();
#elif _WIN32
DoSomethingElse();
#else
GenerateErrorOrIgnore
Small correction: #ifdef TARGET_OS_MAC will get you always true on both OS X and iOS, as it is defines either 0 or 1 depending on platform, but when APPLE is defined, TARGET_OS_MAC is defined as well, so checking it inside the #ifdef APPLE is worthless.
You might want to use #if TARGET_OS_MAC instead. Same for all TARGET_* macros.
Related
_Static_assert is built-in to some C compilers such as gcc and clang, but it may not be included in all C compilers. I would like to use the _Static_assert functionality while keeping my code as cross-platform as possible. I figured the best way to do this was to test
#ifdef _Static_assert
_Static_assert(0, "Test");
#endif
but that doesn't seem to work out. It compiles, but it does not detect that _Static_assert is defined. Then I figured I could test if the compiler was GCC or not, but I read that having __GNUC__ defined doesn't necessarily prove that the compiler used is GCC. This also doesn't detect other compilers where _Static_assert is defined that I may not know about. So my question is, what is the best way to detect if the compiler supports _Static_assert in the preprocessor?
EDIT:
This is the solution I came up with that suits my purposes. Thanks to #KamilCuk below for the link that helped me out.
// Check that we can use built-in _Static_assert
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
#define WE_HAVE_STATIC_ASSERT 1
#endif
#if WE_HAVE_STATIC_ASSERT
_Static_assert(0, "Test");
#endif
This code works for me on both gcc and clang: https://godbolt.org/z/svaYjWj4j
FINAL EDIT (I think): This provides an answer to my original question about how to detect if _Static_assert is available. It also provides a fallback option that results in relatively helpful errors in most compilers I tested.
Here is the link to the test code: https://godbolt.org/z/TYEj7Tezd
// Check if we can use built-in _Static_assert
#if defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 201112L
#define MY_STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#else // We make our own
// MY_JOIN macro trick generates a unique token
#define MY_JOIN2(pre, post) MY_JOIN3(pre, post)
#define MY_JOIN3(pre, post) pre ## post
#if defined( __COUNTER__ ) // try to do it the smart way...
#define MY_JOIN(pre) MY_JOIN2(pre, __COUNTER__)
#define MY_STATIC_ASSERT(cond, msg) \
static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
#else // we did our best...
//will break if static assert on same line in different file
#define MY_JOIN(pre) MY_JOIN2(pre, __LINE__)
#define MY_STATIC_ASSERT(cond, msg) \
static const char *MY_JOIN(static_assert)[(cond) * 2 - 1] = { msg }
#endif
#endif
/* - CHANGE CODE HERE TO TEST THE ASSERTIONS - */
enum {
A = 3,
B = 3,
C = B - A
};
/* - --------------------------------------- - */
// Test to see if the enum values match our assertions
MY_STATIC_ASSERT(B > A, "B must be greater than A");
MY_STATIC_ASSERT(C > 0, "C must be greater than zero");
Helpful information I used to make this came from these links:
http://jonjagger.blogspot.com/2017/07/compile-time-assertions-in-c.html
https://www.tutorialspoint.com/cprogramming/c_preprocessors.htm
https://stackoverflow.com/a/43990067/16292858
How do I test if _Static_assert is defined?
_Static_assert is part of C11. So check for C11.
#if __STDC_VERSION__ > 201112L
You could also #include <assert.h> and check for #ifdef static_assert.
My first google hit for static_assert.h github has a nice example how to handle different tools and compilers: https://github.com/wc-duck/dbgtools/blob/master/include/dbgtools/static_assert.h#L68 .
If you want to write a C11 compatibility layer and use static assertion in your code, for example use this answer and fallback to your own wrapper:
// static_assert.h
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond) \
typedef struct { int static_assertion_failed : !!(cond); } \
CTASTR(static_assertion_failed_,__COUNTER__)
#include <assert.h>
#ifndef static_assert
#define static_assert(expr, str) STATIC_ASSERT(expr)
#endif
// somefile.c
#include <static_assert.h>
static_assert(something == something, "Uwu");
My question should not be too hard to answer:
I am trying to write a C program just to train up some C skills.
However I can't tell on which system this program will run in the future.
I want to make sure I have covered both Unix and DOS systems.
I am trying to do it like this:
#ifdef _WIN32
#define clear()
system("cls");
#endif // _WIN32
#ifdef linux
#define clear()
system("clear");
#endif // linux
This seems to be wrong, as it tells me
expected declaration specifiers or '...' before string constant"
Although I'm not sure if I am doing it right at all with this definitions (I could include 2 separate headers here for example >> more memory used)
There must be kind of a hard newbish syntax error here.
Macro expansion should be on the same line as the macro name. If you really want them over two lines, use \ to "escape" the newline.
#ifdef _WIN32
#define clear() system("cls");
#endif // _WIN32
#ifdef linux
#define clear() system("clear");
#endif // linux
or
#ifdef _WIN32
#define clear() \
system("cls");
#endif // _WIN32
#ifdef linux
#define clear() \
system("clear");
#endif // linux
I have downloaded and succesfully compiled metis 5.0.2 in a win7 x64 pc
and trying to compile metismex.
I compiled metis with Visual Studio 11 (2012) and using the same compiler from within matlab.
After a lot of experimentation with a ton of errors (mainly owed to paths issues from within the libraries) I have reached a point where I dont know how to proceed, since my knowledge on c and c++ is pretty basic.
So, here's the error :
../GKlib/mat_libs/.\stddef.h(16) : error C2054: expected '(' to follow '_SIZE_TYPE__'
../GKlib/mat_libs/.\stddef.h(19) : error C2085: '_WCHAR_TYPE__' : not in formal parameter list
I found out about the inline functions etc, but since the error is within a library and dont exactly know what I should be doing, here I am. So, the error code is produced here :
typedef __SIZE_TYPE__ size_t;
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
any suggestions on what I should do without messing it up?
(in case I comment out wchar type, I also have the same error on prtdiff_type)
Thanks in advance
P.S: In case it is needed, here's the whole sttdef.h
/* Copyright 2012 The MathWorks, Inc. */
#ifndef _STDDEF_H
#define _STDDEF_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
# define NULL (0)
#else
# define NULL ((void *)0)
#endif
typedef __SIZE_TYPE__ size_t;
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#if (! defined(__cplusplus)) || (! defined(PST_GNU))
# define offsetof(type, field) ((size_t) &((type *)0)->field)
#else
# define offsetof(type, field) \
(__offsetof__(reinterpret_cast<size_t> \
(&reinterpret_cast<const volatile char &> \
(static_cast<type *>(0)->field))))
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _STDDEF_H *
/
Here is a walk-through of what I did. I'm running R2014a with VS2013 on Win8.1 x64.
1) First we compile metis:
Download and extract metis-5.1.0 to some location, say C:\metis-5.1.0
Edit C:\metis-5.1.0\include\metis.h and set #define IDXTYPEWIDTH 64 (for x64 architecture)
Next we generate Visual Studio projects using CMake:
> cd C:\metis-5.1.0
> vsgen -G "Visual Studio 12 2013 Win64"
Before we build the solution, we need to fix a few things first. Some header files are unnecessarily redefining rint function for MSVC (metisbin.h, metislib.h, and gk_arch.h). Remove such lines:
#ifdef __MSC__ /* MSC does not have rint() function */
#define rint(x) ((int)((x)+0.5))
/* MSC does not have INFINITY defined */
#ifndef INFINITY
#define INFINITY FLT_MAX
#endif
#endif
Also in GKlib\gk_externs.h replace all occurrences of __thread with __declspec(thread)
Next open the solution file C:\metis-5.1.0\build\windows\METIS.sln in Visual Stduio, and build ALL_BUILD target (make sure "x64" in "Release" mode is selected).
We are mainly interested in the metis project. Its result should be stored in C:\metis-5.1.0\build\windows\libmetis\Release\metis.lib (a static library).
2) Next we build the MEX-function:
Download metismex and extract it to a folder inside the previous location (C:\metis-5.1.0\metismex-master)
Again we need to fix a few things: first rename metismex.c to metismex.cpp (the C++ compiler is much better than the C compiler in Visual Studio!). Next edit this file and replace: #include <strings.h> with #include <string.h>, and add the following code immediately after it:
#if defined(_WIN32) || defined(_WIN64)
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
Finally start MATLAB, and run the following command to compile the MEX-file:
>> cd('C:\metis-5.1.0\metismex-master')
>> mex -O -largeArrayDims -DWIN32 -DMSC -DUSE_GKREGEX -I../GKlib -I../include -I../libmetis metismex.cpp ../build/windows/libmetis/Release/metis.lib
You should now have the final metismex.mexw64
I should say that I know nothing about the library, so I cannot guarantee it gives correct results after all the above modifications. I'm just showing how to get it to compile. The code was written with Linux/OSX in mind, and relies on many POSIX features not intended for Windows. Also the whole 32 vs. 64 bit is a bit messy...
I expected the code to output suse.sys but it actually prints win.sys. Why is this the case?
#define SYS SUSE
#if SYS == WIN
#define HDR "win.sys"
#elif SYS == SUSE
#define HDR "suse.sys"
#else
#define HDR "default.sys"
#endif
#include HDR
#include <stdio.h>
int main()
{
char *name = HDR;
printf("%s\n", name);
return 0;
}
This is similar to the example in the C Programming language second edition. The .sys files don't contain anything, they have no real use.
The preprocessor comparison with == works on integer values, not strings or names of macros. You should be able to fix this by first defining the macros SUSE and WIN with integer values, e.g.,
#define SUSE 1
#define WIN 2
#define SYS SUSE
After this both SYS and SUSE resolve to the integer 1, and the comparison should work.
However, I would suggest a more conventional approach of defining different macros altogether for the systems, e.g.:
#define SYS_SUSE
//#define SYS_WIN
#if defined(SYS_SUSE)
#define HDR "suse.sys"
#elif defined(SYS_WIN)
#define HDR "win.sys"
#else
#define HDR "default.sys"
#endif
This approach has the advantage of being able to more conveniently specify the system on command-line, makefiles, etc. without depending on the numeric constants being defined in every context:
cc -DSYS_WIN -c foo.c
Sorry for asking very basic question. I would like to set OR condition in #ifdef directive.?
How to do that ?
I tried
#ifdef LINUX | ANDROID
...
..
#endif
It did not work? What is the proper way?
Like this
#if defined(LINUX) || defined(ANDROID)
OR condition in #ifdef
#if defined LINUX || defined ANDROID
// your code here
#endif /* LINUX || ANDROID */
or-
#if defined(LINUX) || defined(ANDROID)
// your code here
#endif /* LINUX || ANDROID */
Both above are the same, which one you use simply depends on your taste.
P.S.: #ifdef is simply the short form of #if defined, however, does not support complex condition.
Further-
AND: #if defined LINUX && defined ANDROID
XOR: #if defined LINUX ^ defined ANDROID