I tried to compile a source code package, and found version-specific issues.
When I do that on my computer, everything goes well; but when I compile it on another computer, it produces a lot of claims that INT32_MAX is not defined. Both computer runs a Debian system, and the difference is my computer uses Testing repo and has gcc 4.9, and the other computer uses Stable repo., which has slightly older gcc 4.7.
Then I have a detailed look inside /usr/include/stdint.h. By surprise, on the computer claiming the undefined macros, all int range macros are defined inside a non-C++ condition:
/**
* I forget the exact definition,
* but it looks like this:
*/
#ifndef __cplusplus ......
......
# define INT32_MIN XXX
# define INT32_MAX XXX
......
#endif
As a result, the package won't see these standard range macros, as it is a C++ project, and uses g++ to compile.
Why the stdint.h of gcc 4.7 is designed like this? Is that means gcc 4.7 don't want me to use those integer ranges with C++, and gcc 4.9 allows it?
And the most important: how should I work around this?
In C++ you're recommended to use std::numeric_limits #include <limits>:
Usage example from cplusplus.com
// numeric_limits example
#include <iostream> // std::cout
#include <limits> // std::numeric_limits
int main () {
std::cout << std::boolalpha;
std::cout << "Minimum value for int: " << std::numeric_limits<int>::min() << '\n';
std::cout << "Maximum value for int: " << std::numeric_limits<int>::max() << '\n';
std::cout << "int is signed: " << std::numeric_limits<int>::is_signed << '\n';
std::cout << "Non-sign bits in int: " << std::numeric_limits<int>::digits << '\n';
std::cout << "int has infinity: " << std::numeric_limits<int>::has_infinity << '\n';
return 0;
}
Include climits or limits.h that contains sizes of integral types. This header defines constants with the limits of fundamental integral types for the specific system and compiler implementation used. The limits for fundamental floating-point types are defined in cfloat ( earlier float.h). The limits for width-specific integral types and other typedef types are defined in cstdint (earlier stdint.h).
You should include cstdint instead of stdint.h
Related
How can we know which operating system the code is running?
e.g.
How to know the operating system like Unix-Linux, Solaris, HP Unix, Windows, Mac etc?
How can we determine operating system in C++ code with boost?
I want to test with Boost v1.41 onwards.
These are things a quick scan of version.hpp/config.hpp revealed:
Live On Coliru
#include <boost/version.hpp>
#include <boost/config.hpp>
#include <iostream>
int main() {
std::cout << "BOOST_VERSION " << BOOST_VERSION << "\n";
std::cout << "BOOST_LIB_VERSION " << BOOST_LIB_VERSION << "\n";
std::cout << "BOOST_PLATFORM " << BOOST_PLATFORM << "\n";
std::cout << "BOOST_PLATFORM_CONFIG " << BOOST_PLATFORM_CONFIG << "\n";
std::cout << "BOOST_COMPILER " << BOOST_COMPILER << "\n";
#ifdef BOOST_LIBSTDCXX_VERSION
std::cout << "BOOST_LIBSTDCXX_VERSION " << BOOST_LIBSTDCXX_VERSION << "\n";
#endif
#ifdef BOOST_LIBSTDCXX11
std::cout << "Compiled with c++11 support enabled\n";
#endif
std::cout << "BOOST_STDLIB " << BOOST_STDLIB << "\n";
std::cout << "BOOST_STDLIB_CONFIG " << BOOST_STDLIB_CONFIG << "\n";
}
Which prints
BOOST_VERSION 106400
BOOST_LIB_VERSION 1_64
BOOST_PLATFORM linux
BOOST_PLATFORM_CONFIG boost/config/platform/linux.hpp
BOOST_COMPILER Clang version 3.8.0 (tags/RELEASE_380/final 263969)
BOOST_STDLIB libc++ version 1101
BOOST_STDLIB_CONFIG boost/config/stdlib/libcpp.hpp
Or on my own machine
BOOST_VERSION 106500
BOOST_LIB_VERSION 1_65
BOOST_PLATFORM linux
BOOST_PLATFORM_CONFIG boost/config/platform/linux.hpp
BOOST_COMPILER GNU C++ version 7.2.0
BOOST_LIBSTDCXX_VERSION 70200
Compiled with c++11 support enabled
BOOST_STDLIB GNU libstdc++ version 20170818
BOOST_STDLIB_CONFIG boost/config/stdlib/libstdcpp3.hpp
Code must be compiled to the specific platform you're targeting so you must know the platform at compile time. For example Linux binaries can't be run on BSD, Solaris, AIX... so checking the OS at runtime makes no sense and is useless
That means the OS needs to be checked via preprocessor directives and not in a C statement. There's Boost.Predef which contains various predefined macros for determining the platform
This library defines a set of compiler, architecture, operating system, library, and other version numbers from the information it can gather of C, C++, Objective C, and Objective C++ predefined macros or those defined in generally available headers. The idea for this library grew out of a proposal to extend the Boost Config library to provide more, and consistent, information than the feature definitions it supports. What follows is an edited version of that brief proposal.
...
BOOST_ARCH_ for system/CPU architecture one is compiling for.
BOOST_COMP_ for the compiler one is using.
BOOST_LANG_ for language standards one is compiling against.
BOOST_LIB_C_ and BOOST_LIB_STD_ for the C and C++ standard library in use.
BOOST_OS_ for the operating system we are compiling to.
BOOST_PLAT_ for platforms on top of operating system or compilers.
BOOST_ENDIAN_ for endianness of the os and architecture combination.
BOOST_HW_ for hardware specific features.
BOOST_HW_SIMD for SIMD (Single Instruction Multiple Data) detection.
You can use BOOST_OS_* and BOOST_PLAT_* for your purpose. For example
#include <boost/predef.h>
// or just include the necessary header
// #include <boost/predef/os.h>
#if BOOST_OS_WINDOWS
#elif BOOST_OS_ANDROID
#elif BOOST_OS_LINUX
#elif BOOST_OS_BSD
#elif BOOST_OS_AIX
#elif BOOST_OS_HAIKU
...
#endif
The full list can be found in BOOST_OS operating system macros and BOOST_PLAT platform macros. BOOST_HW_ can also be used to detect the hardware platform
Demo on Godbolt
See also demo on BOOST_ARCH
For this same program c++11 return 2 1 2, but for c++14 return 2 1 1 to me. I am confused..
#include <iostream>
#include <string>
using namespace std;
int main()
{
char a[2];
cout << sizeof(a) << endl;
std::string b("a");
cout << b.size() << endl;
char c[b.size() + 1];
cout << sizeof(c) << endl;
return 0;
}
char c[b.size() + 1]; is not allowed in Standard C++, any version.
If you find a compiler accepts this then it is a compiler extension, so you should consult the documentation for whichever compiler you used.
The following line is not standard C++.
char c[b.size() + 1];
It is supported by some compilers as an extension. They are not expected to confirm to any standard. They may return whatever makes sense from their implementation point of view when they evaulate sizeof(c).
In addition to the answers, I would like to add that this term is known as Variable Length Array and it is an extension in C++ since C99. VisualC++ compiler always outputs this as an error, however GCC and Clang does not.
Only if you add -pedantic flag to your flags it will output warning: ISO C++ forbids variable length array 'c' [-Wvla]
I'm trying to write a program which uses std::isnan() with MSVC 2010. I include cmath but unfortunately the compiler returns the error:
isnan is not part of the std namespace
Does MSVC 2010 support this function from std (AKA C++11)?
std::isnan is in <cmath> : http://en.cppreference.com/w/cpp/numeric/math/isnan
Your problem is probably VS2010 which has very poor C++11 support. I'd recommend grabbing VS2015 which is much better in that regard.
As can be seen here VS2010 only has _isnan .
Unfortunately, Visual Studio's C++11 support hasn't been that complete until the 2015 version, so you won't be able to utilize the C++ std::isnan functionality. Interestingly, there is a C99 isnan macro, but it's implementation defined and VS 2010 does not seem to have any of those macros. Fortunately though, the MS line of compilers do have their MS specific _ versions of the _isnan functionality. So you could write your own isnan as such:
#include <iostream>
#include <cmath>
#include <cfloat>
#include <limits>
namespace non_std
{
template < typename T >
bool isnan(T val)
{
#if defined(_WIN64)
// x64 version
return _isnanf(val) != 0;
#else
return _isnan(val) != 0;
#endif
}
}
int main(int argc, char** argv)
{
float value = 1.0f;
std::cout << value << " is " <<
(non_std::isnan(value) ? "NaN" : "NOT NaN") << std::endl;
if (std::numeric_limits<float>::has_quiet_NaN) {
value = std::numeric_limits<float>::quiet_NaN();
std::cout << value << " is " <<
(non_std::isnan(value) ? "NaN" : "NOT NaN") << std::endl;
}
return 0;
}
On my machine this produces the output:
1 is NOT NaN
1.#QNAN is NaN
Note that the _isnanf is for 64-bit applications and the _WIN64 macro might not necessarily be defined, so if you target 64 bit be sure to adjust that.
Hope that can help.
Is there any macro in C or C++ represent the max and min value of int32_t and int64_t? I know it can be literally defined by oneself, but it's better if there is a standard macro. Please note I'm not asking about max of int, long ,etc. but intXX_t
In C++, there is std::numeric_limits::min() and std::numeric_limits::max() in the <limits> header:
std::cout << std::numeric_limits<std::int32_t>::min() << std::endl;
and so on. In C, the header <stdint.h> defines INT32_MIN, INT32_MAX etc. These are also available in the C++ <cstdint> header.
In C++ you can use header <limits> and class std::numeric_limts declared in this header.
To know the max and min values of types int32_t and int64_t you can write for example
#include <cstdint>
#include <limits>
//...
std::cout << std::numeric_limits<int32_t>::max() << std::endl;
std::cout << std::numeric_limits<int32_t>::min() << std::endl;
std::cout << std::numeric_limits<int64_t>::max() << std::endl;
std::cout << std::numeric_limits<int64_t>::min() << std::endl;
In C you should include header <stdint.h> and use corresponding macros defined in the header as for example
INT32_MIN
INT32_MAX
INT64_MIN
INT64_MAX
So, I have the following code, and it builds and runs perfectly, tried various values and all is well. You'll notice I use log10 function and I do not include cmath or math.h. Why does it still build and run fine? Are those libraries really needed? Why/Why not? Does it have anything to do with me using visual studio? Like, would it not compile if say I was using a different IDE or command prompt to compile it?
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << "Classify solutions as acidic or nonacidic" << endl<< endl;
//declaring double molar concentration
double mc = 1;
//using while and if statements to calculate pH in fixed notaion and acidic or nonacidic
while (mc != 0)
{
cout << "Please enter a molar concentration (or enter 0 to exit): ";
cin >> mc;
if (mc != 0)
{
cout << "Molar Conentration = " << scientific << mc << endl; //scientific notation
double pH = -log10(mc);
cout << "pH = " << fixed << setprecision(6) << pH << endl; //6 deciumals
if (pH > 7)
{
cout << "Nonacidic" << endl << endl;
}
else if (pH < 7)
{
cout << "Acidic" << endl << endl;
}
else
cout << "Neutral" << endl << endl;
}
}
//end program when inputing 0
cout << "End of Program" << endl;
return 0;
}
The code:
i = i++ + ++i;
may also compile okay, but that doesn't make it a good idea :-)
It would be wise to include headers for library functions that you use. You don't lose any functionality by doing so but you do guarantee the functionality will work (misuse notwithstanding).
Detailed analysis follows.
Even if an implementation is relaxed about this, the standard mandates it. C++11 17.6.2.2 Headers /3 states:
A translation unit shall include a header only outside of any external declaration or definition, and shall include the header lexically before the first reference in that translation unit to any of the entities declared in that header.
The gcc compiler, for example, will grumble bitterly about your code:
xyzzy.cpp: In function 'int main()':
xyzzy.cpp:22:34: error: 'log10' was not declared in this scope
double pH = -log10(mc);
^
As to why VC++ seemingly violates this rule, it has to do with the fact that header files are allowed to include other header files.
If you compile your code to produce pre-processor output (with /P), you'll find a line buried deep within it thus (at least in VS2013):
#line 1 "c:\\blah\\blah\\vc\\include\\cmath"
And a bit of analysis turns up the following hierarchy of includes:
iostream
istream
ostream
ios
xlocnum
cmath
(<xlocnum>, one of the internal headers used by <locale>, appears to need ldexp() from the <cmath> library, though there may be others as well).
That's further evidenced by the fact that VC++ does complain about the following code:
//#include <iostream>
using namespace std;
int main() {
double oneHundred = 100;
int two = log10 (oneHundred);
return two;
}
with:
error C3861: 'log10': identifier not found
but that error disappears the instant you uncomment the iostream inclusion line.
However, as previously stated, that is not behaviour you should rely on. If you are going to use a library function (or macro/template/whatever), it's up to you to include the correct header.
Otherwise your program compiling correctly is simply an accident.
As you've noticed, the code snippet you provided works in Visual Studio but not with other compilers. This is because of how the standard library is implemented for each compiler.
It turns out that when you include Visual Studio's implementation of <iostream>, you end up including a bunch of other headers indirectly, and one of these headers is <cmath>.
To see the exact chain, navigate to the standard library include directory. For me (I use Visual Studio 2013 Community Edition) this is located at
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include
Open iostream. Note the line #include <istream>
Open istream. Note the line #include <ostream>
Open ostream. Note the line #include <ios>
Open ios. Note the line #include <xlocnum>
Open xlocnum. Note the line #include <cmath>
Guess what? You included cmath when you included iostream... so your code is good to go, on Visual Studio at least. But, don't rely on implementation details or your code will break if you try to migrate it to another platform/toolchain.
For example, trying to compile the provided snippet using g++ on Cygwin results in the following error:
temp.cpp: In function ‘int main()’:
temp.cpp:22:34: error: ‘log10’ was not declared in this scope
double pH = -log10(mc);
This must mean g++'s implementation of <iostream> doesn't depend on <cmath>