Updating legacy C code headers to C++ stdlib - c++

Inherited a slew of legacy C code, and am in the process of porting it to compile on Linux with GCC (g++). Since we are going to be using C++ in the future and I'm fixing the "custom" library header files anyways (and compiler warnings), is it safe to update the old C headers to use the newer C++ style ones.
So things like
#include <cstdlib>
Instead of
#include <stdlib.h>
To my knowledge the only difference between the two is that cstdlib has things in the std:: namespace.
Would anything make this a bad idea?

Your code may change in very subtle ways, due to the fact that the C++ standard headers use overloading where C used different names. This is most likely to cause trouble with cmath.
stdlib.h isn't going anywhere, so feel free to keep using it.
For example, compare:
#include <iostream>
using namespace std;
#include <stdlib.h>
#include <math.h>
int main(void)
{
double x = -2;
cout << (3/abs(x)) << endl;
return 0;
}
The results before and after switching to C++ headers are very different, even though the exact same C++ compiler and options are used in both cases.

They're exactly the same (on most systems) except for the namespace thing.

Related

C++ "size_t" doesn't need "cstddef" header?

I'm learning C++ with the book C++ Primer, and it says that "size_t" is defined in "cstddef" header, but in this exercise:
#include <iostream>
using namespace std;
int main()
{
int ar[10];
for (size_t x = 0; x < 10; ++x)
ar[x] = x;
for (auto a : ar)
cout << ar[a] << " ";
cout << endl;
return 0;
}
That doesn't have included the header, Visual Studio 2017 (and c++ shell) compiles the program without error.
size_t is really a grey area. std::size_t is the result type of sizeof, but sizeof is a built-in operator you can use without any #include at all. Consider this complete little program:
// no includes, no using namespace std
int main()
{
auto x = sizeof(int); // x is std::size_t
}
On top of that, Visual C++ has always behaved a bit strangely here. Even with settings like /permissive- /std:c++latest in the newest version of the compiler, it still allows the following illegal code:
// no includes, no using namespace std
int main()
{
size_t i = 0;
}
In fact, it would even allow this:
// no includes, no using namespace std
int main()
{
int ar[10];
for (size_t x = 0; x < 10; ++x)
ar[x] = x;
for (auto a : ar)
;
return 0;
}
Nevertheless, what others said about the indirect inclusion of headers is correct. To be precise, the C++ standard says the following about standard-library headers at ยง20.5.5.2:
A C++ header may include other C++ headers.
Which means that Visual C++ behaves correctly in your case anyway. Once you include <iostream>, the implementation is free to indirectly include one of the six standard C++ headers that define std::size_t, and your using namespace std; (which is evil) does the rest.
The C++ standard even guarantees some of such indirect inclusions, but this isn't one of them, so in order to make your code compatible with other compilers, you are strongly encouraged to include <cstddef> or one of the others that guarantee std::size_t.
Standard headers are allowed to include other standard headers. Since headers in different implementations have different dependencies, you should still try to explicitly include everything that you need. It's possible that your program wouldn't build on Linux's libstdc++ or macOS's libc++, for instance.
Standard header will usually include other standard headers, so in many cases you might get away with not including proper ones.
The problem is that such relations between headers are not in the standard e.g. depend on implementatation. If you don't include required headers, your code might work on one compiler, but might fail on another.
Usually if you know that something defined in header X uses type T in its definition, you might assume type T will be available after including X. For example <vector> uses std::size_t as part of std::vector definition, so it will usually include <cstddef>.
Sometimes forward declarations can be used to avoid including other standard headers. But this is only possible with classes and structures, not typedefs.
Some implementations, like GNU Libc for example, are more strict and try to avoid including standard headers internally. Others, like MSVC, are less strict. Code that works with GNU Libc will usually work with MSVC.
It is hard to verify that your code includes everything you need. There are tools that can help you find missing include's, but building your code with multiple compilers is usually the best way to find those issues.
Nope, std::size_t might be defined in multiple headers:
Defined in header <cstddef>
Defined in header <cstdio>
Defined in header <cstdlib>
Defined in header <cstring>
Defined in header <ctime>
Defined in header <cwchar>
Also note, that <iostream> itself includes other headers.
Firstly, std::size_t is defined in a number of standard headers: <cstddef>, <cstdio>, <cstdlib>, <cstring>, <ctime>, and <cwchar>.
Without #includeing one of these, your code is not required to compile.
Practically, a lot of implementations of the standard library have various standard headers #include each other, in which case your code will compile. It is pretty common, but NOT guaranteed, for at least one of the headers that defines std::size_t (or even their C header equivalents like <stddef.h>) to be included by other headers in the C++ standard library.
More specifically, a lot of parts of the standard library work use dynamic memory allocation (standard containers, stream buffers, etc). An obvious - but not required - implementation choice is that they use size_t to represent sizes. For example, standard containers like std::vector have an associated size_type, and std::vector<any_type>::size_type can be, and often is, equivalent to std::size_t.
<iostream> (along with headers it automatically #includes) is not required to include a header that defines std::size_t, but - equally - nothing in the standard disallows it.
In the end it comes down to how cautious you want to be concerning portability. If <iostream> brings in a definition of std::size_t with your particular compiler, then your code will compile. It is possible (although unlikely in practice, not impossible) that a future release of your compiler will update the standard headers to change that. If you intend to port your code to another implementation (compiler and standard library) in future, there is a greater likelihood your code will need to be modified.
Practically, there is no harm by explicitly #includeing <cstddef> or any other header that defines std::size_t. That way, your code that uses std::size_t will compile, regardless of how other standard headers vary between implementations.

Compiling without (necessary?) #include

Consider the following code:
#include <iostream>
using namespace std;
int main () {
srand(time(0));
double dd [10];
for(int i=0;i!=10; ++i) dd[i]= rand()%5+0;
for(auto i:dd)
cout<<i<<' ';
cout<<endl;
exit(100);
}
Why is it compiling without the #include<ctime> and #include<cstdlib> for the calls to time(0) and exit(100)(which is absolutely useless there, I know)? Are they already included in iostream?
The C++ standard, section 17.6.5.2 [res.on.headers], says:
A C++ header may include other C++ headers.
Which means an implementation is free to include other headers when you include one of them. From an implementor's point of view, that's just quite practical, of course.
There are even headers which are guaranteed to include others. For example, <string> implies <initializer_list>.
As for <iostream>, it implies <ios> (which itself implies <iosfwd>), <streambuf>, <istream> and <ostream>. So there is no guarantee for <ctime> and <cstdlib>, and you should include them explicitly for better portability.
To find out which headers are guaranteed to include others, you can either have a look yourself in the standard or in a draft (see all the synopses starting in section 18), or just go to cppreference.com, for example http://en.cppreference.com/w/cpp/header/iostream for <iostream>. It's quite a reliable online C++ reference.
Or you just explicitly include every header you need. Which may be the best choice in the end.
Yes, iostream includes cstdlib (at least in your case; you should not rely on that dependency chain).
Your compiler might have an option to list the dependencies, e.g. for the GNU C compiler, you can use the -M flag to list all includes.

C++ I/O library

I tried googling this but I get different answers at different places. I want to know the cases wherein one should use one of the following:
#include <stdio>
#include <cstdio>
#include <iostream>
I cannot figure out the difference since in my case all my C++ programs seem to work if I use these interchangeably. That being said, iostream seems to support the stream of input and output by defining cin and cout etc. However, I maybe wrong. I would appreciate answers / credible citations for the usage of these with reference to the C++ standards. I wonder if there are any performance benefits involved in using one over the other.
Nonstandard Headers
<stdio> is not defined in any of the standards that I know of.
Standardized Headers for C
<stdio.h> is the c header containing functions like printf() and scanf().
Standardized Headers for C++
<stdio.h> is included in the c++ standard but is deprecated.
<cstdio> is the c++ header that includes things like printf() and scanf().
<iostream> is a c++ header that include things like std::cout, std::cerr and std::cin.
stdio is for standard IO in C. It should have a .h at the end. In C++, all C headers have been encapsulated in cxxxxxx headers (without .h). So, <stdio.h> is the same as <cstudio>. These offer functions, like printf and scanf, for simple IO.
iostream on the other hand is an IO library for C++, and offers streams like cin and cout, as you mentioned.
Depending on your application you can use them interchangeably for most of the time. The syntax is going to be different, obviously.
Formatting text can be easier using the C functions. For example:
printf("item %04d has a value of %+.6e\n", index, value);
is easier to write than (needs <iomanip> in addition to <iostream>):
std::cout << "item " << std::setw(4) << std::setfill('0') << index
<< "has a value of " << std::setprecision(6) << value << "\n";
However, you need to be more careful when using the first one. For example, the following line won't produce a compile error (but as sharth mentioned, you might get warnings when compiling) but will cause runtime issues:
printf("I wonder what will happen? %d\n");
I don't think there is a lot of difference in their performance as most of the stream "magic" happens in compile time, and they should produce similar results. I'm not 100% sure though, so correct me if I'm wrong.
there is no stdio (stdio.h and cstdio). the 'c' and the missing '.h' in the header name indicates that it's the C++ version of the C header.
check cstdio and iostream (references)
some compilers (including MSVC) include stl headers in other stl headers which leads to the effect you observed. this is not portable though!
if you are concerned with performance: use the C++ variants and check this

Which C++ version has #include iostream.h already defined? "didn't have to use std::"

When I took my second programing class this was the version. (long time ago)
My teacher let me take it home to practice it was on 5-7 disk (3.5 floppy) to install.
I believe it's Turbo C++ Professional 2.0
It had templates, projects options and used the standard mini square blue screen (ide).
You didn't have to use any extra includes or statements for input, output.
With time that old PC went, taking the software with it.
(yes I do have newer versions like builder 5,6)
If anyone knows the version please let me know Thanks ahead of Time.
Borland C++ 3.1, too.
Visual C++ 6.0 and older.
iostream.h is the deprecated version.
use #include < iostream >
Namespaces help avoiding name collisions. The current standard has #include <iostream> substituting the previous #include <iostream.h>. You should get used to the std:: prefix to identify the namespace where the standard libraries live, or you can apply using directives to avoid having to write std:: all around:
#include <iostream>
using namespace std;
int main() {
cout << "No std:: required here" << endl;
}
The using directive tells the compiler to bring all identifiers from the namespace here, avoiding the need for qualification. Note that in the presence of ambiguities you will still need to fully qualify.
#include <iostream>
int cout;
int main() {
using namespace std;
::cout = 5;
std::cout << ::cout << endl;
}
iostream.h was a part of the standard library as documented by C++ Annotated Reference Manual (which was a de facto standard document prior to ISO standardization of the language).

no std namespace

We've got a reasonable sized C++ application that's pretty old at this stage, so it's got a few quirks.
One of these quirks is in how it deals with C++ compilers that use a pre-standisation standard library. There's one header file that's supposed to resolve any differences between a standards compliant compiler and this one non-compliant compiler. For various reasons we can't / don't want to stop supporting this compiler.
#include <vector>
#include <set>
#if defined(NO_STD_LIB)
#include <iostream.h>
#else
#incude <iostream>
using std::string;
using std::cout;
using std::vector;
using std::cout;
#endif
You use this as follows
#include stl.h
int main() {
vector<string> foo;
.....
return 0;
}
There are 2 main issues with this approach:
Each compilation unit that includes std.h has to compile lots of un-needed code (and we're trying to reduce compile times as much as possible at the minute)
The global namespace gets polluted with pretty much everything that would normally be in the std namespace.
I really would like to address both of these points as part of a code cleanup project. The first one really is the more important reason for doing this.
As we have to support this old compiler then our code will always have to avoid clashing names with things that it exposes in it's standard lib, so point 2 isn't really relevant, though I'd like to see a solution that works when / if we can finally drop support for it.
My idea so far is to break up the super header into a set of smaller headers. e.g. stl_vector, stl_iostream, stl_set, etc. This way we can only include the parts of the standard library that we're interested in. These filenames follow the pattern of the std headers, but with an easily searched for prefix. So when the time comes to dump the offending compiler, it'll be simple to search for the prefix and remove it.
I think that will fix issue 1 easily enough.
My real problem is fixing issue 2. I thought of doing someting like this
#if defined(NO_STD_LIB)
#include <iostream.h>
#define std
#else
#include <iostream>
then we could code as follows:
#incude "stl_iostream"
int main() {
std::string foo("bar");
std::cout << foo << std::endl;
}
And that almost worked. Where there was no standard namespace the #define std made std::string decompose into ::string and life was good.
Then I tried this with a .cc file that used the dreaded "using namespace std;" and I get a compile error because that becomes "using namespace ", so that obviously won't work.
Now obviously I could ban people from writing "using namespace std;", but as much as it should be avoided in headers, it's sometimes useful in .cc files where you're making heavy use of lots of STL classes.
So, finally, to the question. Is there a standard idiom for dealing with this issue. Or if there isn't a standard way to deal with this, then what tricks do you use to support compilers that use a pre-standard standard library.
I've thought of using pre-compiled headers to solve the compilation speed issue, but we target different compilers and the effort of getting this working across all of them may mean its not worth our time doing it.
Answers that advise me to drop the non-conforming compiler may be popular, but won't be accepted as this is something that we can't do just now.
You can try:
#if defined(NO_STD_LIB)
namespace std {
using ::string;
using ::cout;
using ::vector;
using ::cout;
}
#endif
Then std::string will work.
It would have been much better if the using namespace ::; directive existed in the language; however it doesn't.