I'm confused about the struct definitions below. Shouldn't be both correct? With Borland C both compile, but with gcc only the second one compiles. The error is "unknown type name _Node".
typedef struct _Node {
int item;
_Node* next;
} Node;
typedef struct _Node {
int item;
struct _Node* next;
} Node;
It depends on how the compiler handles forward references. The gcc compiler may do,this by default since it is also a C++ compiler.
No, in C only the second (explicitly including the struct specifier) is correct. While C++ allows the omission of struct, c does not, so this is a non-portable Borland extension. If you compile with g++, I imagine it should accept the first syntax as well.
Related
With gcc 10.1 and boost 1.73.0, the following code
#include <boost/bimap.hpp>
int main() {
boost::bimap<int, int> lookup;
}
fails to compile with flags -O2 --std=c++20, but will succeed with flags -O2 -std=c++17 (verified with compiler explorer).
This is possibly related to the following issue: https://github.com/boostorg/bimap/pull/15 (deprecated std::allocator<void>)
Is there some workaround I can use for now to get this code to successfully compile with --std=c++20?
The reason behind the error is not that the std::allocator<void> specialization is removed. Actually, it's still valid as the primary template with the void argument. The code fails to compile, because ::rebind is no longer part of std::allocator itself. Instead, an implementation should use std::allocator_traits<Alloc>::rebind_alloc<U>.
Fortunately, most containers usually allow to specify a custom allocator as a template argument. It's also the case for boost::bimap, where an allocator can be the third, fourth or fifth template parameter, according to docs. It defaults to std::allocator, but instead, boost::container::allocator can be used, which does not produce the error:
#include <boost/bimap.hpp>
#include <boost/container/allocator.hpp>
int main() {
boost::bimap<int, int, boost::container::allocator<int>> lookup;
}
This issue has recently been fixed in 6fba6e5. boost::bimap now properly detects if a nested ::rebind is available:
template<class A, class T, class = void>
struct allocator_rebind {
typedef typename detail::alloc_to<A, T>::type type;
};
template<class A, class T>
struct allocator_rebind<A, T,
typename detail::alloc_void<typename A::template rebind<T>::other>::type> {
typedef typename A::template rebind<T>::other type;
};
Background of this question : I am trying to understand how compilers work. I learn many new things : scanner, parser, AST, IR, optimisation, frontend, backend,LL(1), ... I made gradual progress and it is very interesting. Now, I would like to do some practical works.
From a programmer point of view, I know why typedef struct { int x; mytype* next; } mytype; does not compile and I know the correct syntax typedef struct mystruct { int x; struct mystruct* next; } mytype; but I would like to know where the problem happens EXACTLY during compilation. I am using gcc, I would like to know how is it posible to use gcc developper options -fdump-... to answer this question.
The first step of the GCC compiler work is parser
c-parser.c
It parse your c or c++ or some else code into gimple representation:
Parse -> Gimplify -> Tree -> SSA -> Optimize -> Generate -> RTL -> Optimize RTL Generate -> ASM
Errors can be found, for example, in terminal, or in IDE in error output like next:
gcc yourcode.c
yourcode.c:2:25: error: unknown type name 'mytype'
typedef struct { int x; mytype* next; } mytype;
^~~~~~
You also can look at how it works via a
link
Sorry for my English.
It seems that we can not give a default value for struct members in c++,but I find that code as below can compile and run, why? Am I missing something?
struct Type {
int i = 0xffff;
};
Program:
#include <iostream>
using namespace std;
struct Type {
int i = 0xffff;
};
int main() {
// your code goes here
Type val;
std::cout << val.i << std::endl;
return 0;
}
It is going to depend on the compiler you use.
For gcc and clang you need to pass the flag -std=c++11 to the compiler.
Support for member initializer and other c++11 features:
gcc since 4.7. See here.
clang since 3.0. See here.
Visual studio compiler in its 2013 version. See here.
This is correct and introduced in C++11 standard. This concept is known as in-class member initializer
You can check Stroustrup FAQ link on this concept:
http://www.stroustrup.com/C++11FAQ.html#member-init
I am trying my C++11 code to see if all recent major compiler supports the features I used, and the following shortened code
#include <valarray>
struct T
{
double vv[3];
};
class V : public std::valarray<T>
{
public:
auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
{
return std::begin(static_cast<std::valarray<T>>(*this));
}
};
int main(void)
{
}
would compile with g++ 4.8.1(from Debian sid repository), Intel C++ compiler 13.1.1 20130313, but not Clang 3.3-2(from Debian sid repository).
The given error is:
test.cpp:11:73: error: no viable conversion from 'V' to 'std::valarray<T>'
auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
^~~~~
However, code like this
namespace std
{
auto begin(V& vv) -> decltype(std::begin(static_cast<V::parent_t>(vv)))
{
return std::begin(static_cast<V::parent_t>(vv));
}
}
would compile by all three compilers.
My question is: is the code itself allowed by the language standard, just Clang miscompiled it, or it is only supported by g++/icc extension? Or it is undefined behavior?
The code very dangerous and needs to be fixed even for GCC and ICC.
You're doing a static_cast to a value type, not a reference or pointer. That creates a new temporary valarray object, so the const overload of begin gets called (probably not what you intended), and the iterator returned by begin() refers to the temporary which goes out of scope immediately, so the returned iterator is invalid and dereferencing it is undefined behaviour.
The code will compile like this:
auto begin()->decltype(std::begin(std::declval<std::valarray<T>&>()))
{
return std::begin(static_cast<std::valarray<T>&>(*this));
/* cast to reference type! ^^^^^^^^^^^^^^^^^ */
}
The decltype doesn't need to cast this, it just needs to know the type of calling std::begin on a valarray<T>, so it doesn't matter if the type is incomplete because you don't need a cast.
In the body of the function the type is considered complete anyway, so the cast is valid.
I am working on a C++ project on macOS X 10.6.2 with xcode.
I tried to compile my code on windows and do not have any problem, I guess Linux is working but I don't have one with me right now.
My problem is xcode do not accept this kind of instruction :
struct direction {
double x;
double y;
double z;
double t; };
typedef struct direction direction;
Here is my error :
/Users/sbarbier/dev/xcode/Infographie/TP9-RayTracing/RayTracing-Direction.h:22:0 /Users/sbarbier/dev/xcode/Infographie/TP9-RayTracing/RayTracing-Direction.h:22: error: changes meaning of 'direction' from 'typedef struct direction direction'
I am using GCC4.2 and haven't change anything. This code works on every platform, can any one help me ?
This isn't C. In C, to use a struct you had to use the keyword struct:
struct some_struct{ int i; };
struct some_struct myStruct;
This was alleviated like this, commonly:
typedef struct { int i; } some_struct;
some_struct myStruct;
In C++ this is not required. direction already has a type, then you're trying to make a new type of the same name, and that's bad. Take out your entire typedef, it isn't needed.
In C++, struct and class are used only when declaring or defining the struct or class. You might want the typedef in C, but in C++ it doesn't make any sense.