The following code is rejected by both clang and gcc but accepted by msvc:
#include <iostream>
int main()
{
std::cout << unsigned long long(10);
}
The error is
error: expected primary-expression before 'unsigned'
godbolt
This should compile, right?
No, what you have shown should NOT compile. See Explicit type conversions on cppreference.com for details.
In a function-style cast, spaces are not allowed in the type name. For such types, you would need to use a C-style or C++-style cast instead, eg:
std::cout << ((unsigned long long)10);
or
std::cout << static_cast<unsigned long long>(10);
Otherwise, use a type alias instead, eg:
using ull = unsigned long long; // C++11 and later
or
typedef unsigned long long ull; // pre-C++11
std::cout << ull(10);
Note, the <cstdint> header may have a uint64_t type you can use, eg:
#include <cstdint>
std::cout << uint64_t(10);
or
std::cout << ((uint64_t)10);
or
std::cout << static_cast<uint64_t>(10);
That being said, for integer literals, you can alternatively use the ULL suffix (C++11 and later), eg:
std::cout << 10ULL;
Related
gcc fails to compile the code below, while clang compiles ok. I have no control on the macro PORTB, as it is in a 3rd party library (avr).
Is it a gcc bug? How can I work around it in gcc? As a workaround is somehow possible to create a pre-processor macro which extracts the numerical value from PORTB?
Note this question is similar, but not identical to my previous question.
It is also different from this question, where the developer has the flexibility to change the rhs of the assignment, thus avoiding the reinterpret_cast.
#include <iostream>
#include <cstdint>
#define PORTB (*(volatile uint8_t *)((0x05) + 0x20))
struct PortB {
static const uintptr_t port = reinterpret_cast<uintptr_t>(&PORTB);
};
int main() {
std::cout << PortB::port << "\n";
return 0;
}
It seems reinterpret_cast is not allowed during compilation. Thus the newer version of the compiler simply is more conforming to the language. reinterpret_cast will not be allowed where a constexpr is required.
But maybe these workaround may help (compiles with g++ 9.2):
#include <iostream>
#include <cstdint>
#define PORTB (*(volatile uint8_t *)((0x05) + 0x20))
struct PortB {
static uintptr_t port;
};
uintptr_t PortB::port = reinterpret_cast<uintptr_t>(&PORTB);
const uintptr_t freePort = reinterpret_cast<uintptr_t>(&PORTB);
#define macroPort reinterpret_cast<uintptr_t>(&PORTB)
int main() {
std::cout << PortB::port << "\n";
std::cout << freePort << "\n";
std::cout << macroPort << "\n";
return 0;
}
The code I have been working on requires that I print a variable of type uint32_t in hexadecimal, with a padding of 0s and minimum length 8. The code I have been using to do this so far is:
printf("%08lx\n",read_word(address));
Where read_word returns type uint32_t. I have used jx, llx, etc. formats to no avail, is there a correct format that can be used?
EDIT:
I have found the problem lies in what I am passing. The function read_word is returns a value from a uint32_t vector. It seems that this is the problem that is causing problems with out putting hex. Is this a passing by reference/value issue and what is the fix?
read_word function:
uint32_t memory::read_word (uint32_t address) {
if(address>(maxWord)){
return 0;
}
return mem[address];
}
mem deceleration:
std::vector<uint32_t> mem=decltype(mem)(1024,0);
To do this in C++ you need to abuse both the fill and the width manipulators:
#include <iostream>
#include <iomanip>
#include <cstdint>
int main()
{
uint32_t myInt = 123456;
std::cout << std::setfill('0') << std::setw(8) << std::hex << myInt << '\n';
}
Output
0001e240
For C it gets a little more obtuse. You use inttypes.h
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint32_t myInt = 123456;
printf("%08" PRIx32 "\n", myInt);
return 0;
}
Output
0001e240
Note that in C, the constants from inttypes.h are used with the language string-concatenation feature to form the required format specifier. You only provide the zero-fill and minimum length as a preamble.
%jx + typecast
I think this is correct:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint32_t i = 0x123456;
printf("%08jx\n", (uintmax_t)i);
return 0;
}
compile and run:
gcc -Wall -Wextra -pedantic -std=c99 main.c
./a.out
Output:
00123456
Let me know if you can produce a failing test case.
Tested in Ubuntu 16.04, GCC 6.4.0.
This question already has an answer here:
undefined behaviour somewhere in boost::spirit::qi::phrase_parse
(1 answer)
Closed 7 years ago.
I have a little grammar that I want to use for a work project. A minimum executable example is:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#pragma GCC diagnostic pop // pops
#include <iostream>
int main()
{
typedef unsigned long long ull;
std::string curline = "1;2;;3,4;5";
std::cout << "parsing: " << curline << "\n";
namespace qi = boost::spirit::qi;
auto ids = -qi::ulong_long % ','; // '-' allows for empty vecs.
auto match_type_res = ids % ';' ;
std::vector<std::vector<ull> > r;
qi::parse(curline.begin(), curline.end(), match_type_res, r);
std::cout << "got: ";
for (auto v: r){
for (auto i : v)
std::cout << i << ",";
std::cout << ";";
}
std::cout <<"\n";
}
On my personal machine this produces the correct output:
parsing: 1;2;;3,4;5
got: 1,;2,;;3,4,;5,;
But at work it produces:
parsing: 1;2;;3,4;5
got: 1,;2,;;3,
In other words, it fails to parse the vector of long integers as soon as there's more than one element in it.
Now, I have identified that the work system is using boost 1.56, while my private computer is using 1.57. Is this the cause?
Knowning we have some real spirit experts here on stack overflow, I was hoping someone might know where this issue is coming from, or can at least narrow down the number of things I need to check.
If the boost version is the problem, I can probably convince the company to upgrade, but a workaround would be welcome in any case.
You're invoking Undefined Behaviour in your code.
Specifically where you use auto to store a parser expression. The Expression Template contains references to temporaries that become dangling at the end of the containing full-expression¹.
UB implies that anything can happen. Both compilers are right! And the best part is, you will probably see varying behaviour depending on the compiler flags used.
Fix it either by using:
qi::copy (or boost::proto::deep_copy before v.1.55 IIRC)
use BOOST_SPIRIT_AUTO instead of BOOST_AUTO (mostly helpful iff you also support C++03)
use qi::rule<> and qi::grammar<> (the non-terminals) to type-erase and the expressions. This has performance impact too, but also gives more features like
recursive rules
locals and inherited attributes
declared skippers (handy because rules can be implicitly lexeme[] (see here)
better code organization.
Note also that Spirit X3 promises to drop there restrictions on the use with auto. It's basically a whole lot more lightweight due to the use of c++14 features. Keep in mind that it's not stable yet.
Showing that GCC with -O2 shows undefined results; Live On Coliru
The fixed version:
Live On Coliru
//#pragma GCC diagnostic push
//#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
//#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
//#pragma GCC diagnostic ignored "-Wunused-variable"
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/qi.hpp>
//#pragma GCC diagnostic pop // pops
#include <iostream>
int main() {
typedef unsigned long long ull;
std::string const curline = "1;2;;3,4;5";
std::cout << "parsing: '" << curline << "'\n";
namespace qi = boost::spirit::qi;
#if 0 // THIS IS UNDEFINED BEHAVIOUR:
auto ids = -qi::ulong_long % ','; // '-' allows for empty vecs.
auto grammar = ids % ';';
#else // THIS IS CORRECT:
auto ids = qi::copy(-qi::ulong_long % ','); // '-' allows for empty vecs.
auto grammar = qi::copy(ids % ';');
#endif
std::vector<std::vector<ull> > r;
qi::parse(curline.begin(), curline.end(), grammar, r);
std::cout << "got: ";
for (auto v: r){
for (auto i : v)
std::cout << i << ",";
std::cout << ";";
}
std::cout <<"\n";
}
Printing (also with GCC -O2!):
parsing: '1;2;;3,4;5'
got: 1,;2,;;3,4,;5,;
¹ (that's basically "at the next semicolon" here; but in standardese)
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
When using the double variant of the std::abs() function without the std with g++ 4.6.1, no warning or error is given.
#include <algorithm>
#include <cmath>
double foobar(double a)
{
return abs(a);
}
This version of g++ seems to be pulling in the double variant of abs() into the global namespace through one of the includes from algorithm. This looks like it is now allowed by the standard (see this question), but not required.
If I compile the above code using a compiler that does not pull the double variant of abs() into the global namespace (such as g++ 4.2), then the following error is reported:
warning: passing 'double' for argument 1 to 'int abs(int)'
How can I force g++ 4.6.1, and other compilers that pull functions into the global namespace, to give a warning so that I can prevent errors when used with other compilers?
The function you are using is actually the integer version of abs, and GCC does an implicit conversion to integer.
This can be verified by a simple test program:
#include <iostream>
#include <cmath>
int main()
{
double a = -5.4321;
double b = std::abs(a);
double c = abs(a);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << '\n';
}
Output is:
a = -5.4321, b = 5.4321, c = 5
To get a warning about this, use the -Wconversion flag to g++. Actually, the GCC documentation for that option explicitly mentions calling abs when the argument is a double. All warning options can be found here.
Be warned, you don't need to explicitly #include <cmath>, <iostream> does the damage as well (and maybe some other headers). Also, note that -Wall doesn't give you any warnings about it.
#include <iostream>
int main() {
std::cout << abs(.5) << std::endl;
std::cout << typeid(decltype(abs)).name() << std::endl;
}
Gives output
0
FiiE
On
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)