So I know any header from the C Compatability Headers:
Places in the global namespace each name that the corresponding cxxx header would have placed in the std namespace
I also know that these C headers were deprecated as of c++17, in favor of their compatibility "cxxx" counterparts.
Now, I believe that size_t is defined exclusively by the Standard Defines Header. So I presume this technically means that the definition of size_t in the global namespace has been deprecated?
I've been using it for years as just size_t and I'd just like a confirmation before I move to using std::size_t.
I presume this technically means that the definition of size_t in the global namespace has been deprecated?
Yes... but.
The Standard only mandates that std::size_t must be defined1 by <cstddef>, it does not disallow an implementation to define ::size_t2, but if the implementation does, the two definitions must match3.
As a conclusion, you should use std::size_t and should neither rely on ::size_t to be defined nor define it.
The following are UB:
// DON'T
using size_t = std::size_t; // UB
using size_t = decltype(sizeof 1); // UB
1) [cstddef.syn]
namespace std {
using ptrdiff_t = see below;
using size_t = see below;
using max_align_t = see below;
using nullptr_t = decltype(nullptr);
[...]
The contents and meaning of the header <cstddef> are the same as the C standard library header <stddef.h>, except that it does not declare the type wchar_t, that it also declares the type byte and its associated operations ([support.types.byteops]), and as noted in [support.types.nullptr] and [support.types.layout].
2)[extern.types]/1
For each type T from the C standard library (These types are [...] size_t,[...].), the types ::T and std::T are reserved to the implementation[.]
3)[extern.types]/1
[...] when defined, ::T shall be identical to std::T.
C-style header names like <stddef.h> are deprecated. However, C++-style headers like <cstddef> are allowed to declare their names in global namespace and then redeclare the same names in namespace std through using-declarations (http://eel.is/c++draft/organization#headers-4). This approach to declaring standard names is not deprecated. And many implementations do exactly that, for which reason it is not unusual to see name size_t accessible as a name from global namespace. But this is not guaranteed. So, in portable C++ code that includes <cstddef> you should use std::size_t and never rely on ::size_t's availability.
The standard says [expr.sizeof]:
The result of sizeof and sizeof... is a constant of type std::size_t. [ Note: std::size_t is defined in the standard header <cstddef> ([cstddef.syn], [support.types.layout]). — end note ]
Where is size_t Defined?
::size_t is guaranteed to be defined in <stddef.h> and few other C standard library headers that are inherited by c++. It may be defined by the implementation whether anything is included or not, since it is reserved, but relying on such non guaranteed definition would not be wise.
So I presume this technically means that the definition of size_t in the global namespace has been deprecated?
Indeed. More precisely, all standard headers that are guaranteed to define ::size_t are now deprecated in C++17. Same applies to all other non-macro C library names such as ::FILE.
Related
#include <iostream>
#include <cmath>
/* Intentionally incorrect abs() which seems to override std::abs() */
int abs(int a) {
return a > 0? -a : a;
}
int main() {
int a = abs(-5);
int b = std::abs(-5);
std::cout<< a << std::endl << b << std::endl;
return 0;
}
I expected that the output will be -5and 5, but the output is the -5 and -5.
I wonder why this case will happen?
Does it have anything to do with the use of std or what?
The language specification allows implementations to implement <cmath> by declaring (and defining) the standard functions in global namespace and then bringing them into namespace std by means of using-declarations. It is unspecified whether this approach is used
20.5.1.2 Headers
4 [...] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (6.3.6) of the namespace std. It is unspecified whether these names (including any overloads
added in Clauses 21 through 33 and Annex D) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (10.3.3).
Apparently, you are dealing with one of implementations that decided to follow this approach (e.g. GCC). I.e. your implementation provides ::abs, while std::abs simply "refers" to ::abs.
One question that remains in this case is why in addition to the standard ::abs you were able to declare your own ::abs, i.e. why there's no multiple definition error. This might be caused by another feature provided by some implementations (e.g. GCC): they declare standard functions as so called weak symbols, thus allowing you to "replace" them with your own definitions.
These two factors together create the effect you observe: weak-symbol replacement of ::abs also results in replacement of std::abs. How well this agrees with the language standard is a different story... In any case, don't rely on this behavior - it is not guaranteed by the language.
In GCC this behavior can be reproduced by the following minimalistic example. One source file
#include <iostream>
void foo() __attribute__((weak));
void foo() { std::cout << "Hello!" << std::endl; }
Another source file
#include <iostream>
void foo();
namespace N { using ::foo; }
void foo() { std::cout << "Goodbye!" << std::endl; }
int main()
{
foo();
N::foo();
}
In this case you will also observe that the new definition of ::foo ("Goodbye!") in the second source file also affects the behavior of N::foo. Both calls will output "Goodbye!". And if you remove the definition of ::foo from the second source file, both calls will dispatch to the "original" definition of ::foo and output "Hello!".
The permission given by the above 20.5.1.2/4 is there to simplify implementation of <cmath>. Implementations are allowed to simply include C-style <math.h>, then redeclare the functions in std and add some C++-specific additions and tweaks. If the above explanation properly describes the inner mechanics of the issue, then a major part of it depends on replaceability of weak symbols for C-style versions of the functions.
Note that if we simply globally replace int with double in the above program, the code (under GCC) will behave "as expected" - it will output -5 5. This happens because C standard library does not have abs(double) function. By declaring our own abs(double), we do not replace anything.
But if after switching from int with double we also switch from abs to fabs, the original weird behavior will reappear in its full glory (output -5 -5).
This is consistent with the above explanation.
Your code causes undefined behaviour.
C++17 [extern.names]/4:
Each function signature from the C standard library declared with external linkage is reserved to the implementation for use as a function signature with both extern "C" and extern "C++" linkage, or as a name of namespace scope in the global namespace.
So you cannot make a function with the same prototype as the Standard C library function int abs(int);. Regardless of which headers you actually include or whether those headers also put C library names into the global namespace.
However, it would be allowed to overload abs if you provide different parameter types.
Is it possible to remove standard features from C++
//Undefine some function from the standard like classes
class someclass
{
someclass(){
//Whatever
}
};
then get the error
"class undeclared identifier"
Not that I recommend it but you can use pre-processor macros to undefine anything you want.
If you compile the program below, you will get lots of errors.
#define vector
#include <vector>
int main()
{
vector<int> a;
}
You don't need the #define vector in the file. You can define it in the command used to invoke the compiler.
Note that using the above trick makes your program subject to undefined behavior:
From the C++11 Standard:
17.6.4.3 Reserved names
...
2 If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
17.6.4.3.1 Macro names [macro.names]
1 A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
2 A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table [tab:identifiers.special], or to the attribute-tokens described in [dcl.attr].
std::size_t is defined in any of:
<cstddef> <cstdio> <cstdlib> <cstring> <ctime> <cwchar>
Which is considered 'kosher' for getting just std::size_t?
Since this is part of the C library I think the C standard specified header is the right one: stddef.h, i.e. cstddef.
From C11:
7.19 Common definitions
The header defines the following macros and declares the following types. Some are also defined in other headers, as noted in their respective subclauses.
[...]
size_t which is the unsigned integer type of the result of the
sizeof operator;
This is after all a C++ question so I think a quote from the C++ standard is more appropriate:
18.2 Types
Table 30 describes the header <cstddef>.
Types: ptrdiff_t size_t max_align_t nullptr_t
I was playing with ptrdiff_t and reading the C++11 standard when I came across this "issue". First, the facts:
The type ptrdiff_t (just an example) is pulled from the Standard C library header <stddef.h> into <cstddef> (§18.2/2). Section 17.6.1.2 tells us that declarations pulled from the C standard library will be within the std namespace:
In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is
unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
As it also says, the declarations may have been declared in global namespace first and then injected into std. So it would make sense, for my implementation, that the following compiles just fine:
#include <cstddef>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
My implementation (gcc 4.6.3) must have declared ptrdiff_t in the global namespace and then injected it into std. However, if I compile the following code, I get an error (notice the <iostream> include):
#include <iostream>
int main(int argc, const char* argv[])
{
std::ptrdiff_t x;
ptrdiff_t y;
return 0;
}
main.cpp: In function ‘int main(int, const char**)’:
main.cpp:6:3: error: ‘ptrdiff_t’ was not declared in this scope
main.cpp:6:3: note: suggested alternatives:
/usr/include/c++/4.6/i686-linux-gnu/./bits/c++config.h:156:28: note: ‘std::ptrdiff_t’
So, since std::ptrdiff_t is available, <iostream> must be including <cstddef> in some way (although it's not required to). But why is the global version not also available as it
was before? Can I not expect this injection to be consistent even when it's actually the same header? This seems like odd behaviour. Whether the injection occurs may be unspecified, but it should at least be either one way or the other, not both, right?
Do not rely on one header including another, if you want something declared/defined in a specific header then you must include it.
For the example you gave, with g++ there are actually two definitions of ptrdiff_t (and size_t for that matter). The first, in namespace std, that comes from <bits/c++config.h>. And the one in the global namespace from <stddef.h> (and so <cstddef>).
The problem is that you did not using the correct header. You should do
#include <cstddef>
instead. However you use
#include<iostream>
And that has a definition of "std::ptrdiff_t" in it indirectly. However, the global "::ptrdiff_t" is not defined in "iostream" and "iostream" did not include "cstddef" as you thought. Instead, "iostream" does include "bits/c++config.h". The actual "std::ptrdiff_t" is defined in that file.
If you look at the content of the file "cstddef" you will find that is is only two "useful" lines there
BTW, the above discussion is for GCC 4.6 and GCC 4.7. For GCC 4.4, "iostream" indrectly include "cstddef" therefore ptrdiff_t will be available in both namespaces (std and global).
#include
#include
The latter line brings in the global "::ptrdiff_t" and the former defines the std namespace one.
Is this code standard conforming?
#include <stdio.h>
#include <cstdio>
int main() {
FILE *f1 = 0;
std::FILE *f2 = f1;
}
Explanation: The standard says [headers]:
[...] the contents of each header cname shall be the same as that of the corresponding header name.h [...] as if by inclusion. In the C++ standard library, however, the declarations [...] are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).
So in case they aren't injected by explicit using-declaration, may they be different type? I don't think the "as if by inclusion" phrase is conclusive since the other half of the text clearly contradicts this requirement, requiring the names are within the std namespace.
Yes, that's standard conforming: FILE* is declared in stdio.h, std::FILE* in cstdio, and the two are the same because of the paragraph you cited.
(The only thing that's unspecified is whether, if you only include <cstdio>, you also have the same FILE* in the global namespace or not.)
Update: I believe that the types are actually the same on the nose, and that each type is declared only once and then injected in to the other namespace via a using declaration. The only thing that's unspecified is which one comes first. The corresponding opposite standard quote is D.5(2):
Every C header, each of which has a name of the form name.h, behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).
Basically, that means that two implementations are possible:
"C came first":
// foo.h
struct Gizmo { /* ... */ };
// cfoo
#include "foo.h"
namespace std { using ::Gizmo; }
"C++ with C-compatibility:
// cfoo
namespace std
{
struct Gizmo { /* ... */ };
}
// foo.h
#include <cfoo>
using std::Gizmo;
I don't believe that paragraph says that they have to be identical. It is just a revision of the original (C++98) paragraph which said:
Every C header, each of which has a name of the form name.h behaves as if each name placed in the Standard library namespace by the corresponding cname header is also placed within the namespace scope of namespace std and is followed by an explicit using-declaration (7.3.3)
This was between hard and impossible to follow, because it conflicted with the existing real C headers on most systems. So, in C++11 the text was changed to the one you quote. It allows implementations to it the other way round, like they in practice have done all along - use existing system provided C headers and import the names to namespace std.
However, there is another paragraph saying that whichever way the implementation does this, the names in the headers must mean the same thing:
For each type T from the Standard C library, the types ::T and std::T are reserved to the implementation and, when defined, ::T shall be identical to std::T. ([extern.types], 17.6.4.3.4)
Yes, they can be different types. Use the C++ types; the C headers are only there for compatibility.
Consider if as the comment to the answer above suggests, the C++ header were implemented as namespace std { #include "stdio.h" }; then ::FILE and std::FILE would represent different types.