Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can types in `cname` and `name.h` be different types?

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.

like image 297
Yakov Galka Avatar asked May 05 '12 21:05

Yakov Galka


3 Answers

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;
like image 135
Kerrek SB Avatar answered Sep 22 '22 13:09

Kerrek SB


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)

like image 33
Bo Persson Avatar answered Sep 19 '22 13:09

Bo Persson


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.

like image 44
Klemens Baum Avatar answered Sep 20 '22 13:09

Klemens Baum