I am learning about double and float and what the difference is. I ran a piece of code as posted below, to see how much memory is allocated depending on how many integers I add and decimal points but it seems that no matter how many integers I type I always get size 8 bytes for both float and double. I learned that float occupies 4 bytes, but Im starting to think that on modern computers that's not the case and perhaps this was the case back in the days and today we can use them interchangeably without affecting the results? Am I missing something here?
// C++ program to sizes of data types
#include<iostream>
using namespace std;
int main()
{
cout << "Size of int : " << sizeof(11111111111111111) << " bytes" << endl;
cout << "Size of float : " << sizeof(11111111111111111111111111111111111111111111111111111111111.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111) << " bytes" <<endl;
cout << "Size of double : " << sizeof(.11111111111111111111111111111111111111111111111111111) << " bytes" << endl;
return 0;
}
You print the size of double on both lines, because both floating point literals has the type of double. If you want to create a float literal, append an f to it: 1.0f. This has the type of float. If you don't append an f to it, it will have the type of double.
Or you can just simply use sizeof(float).
Related
#include <iostream>
using namespace std;
class V3 {
public:
double x, y, z;
V3(double a, double b, double c) {
x=a;
y=b;
z=c;
cout << "Addresses are " << &x << " " << &y << " " << &z << endl;
}
};
int main() {
V3 a(1,1,1), b(2,2,2), c(3,3,3), d(4,4,4);
cout << sizeof(a) << " " << sizeof(b) << " " << sizeof(c) << " " << sizeof(d) << endl;
}
In the code mentioned above, I'm trying to see how C++ stores objects in memory. On running this code, I get the following output -
Addresses are 0x7ffc5996b160 0x7ffc5996b168 0x7ffc5996b170
Addresses are 0x7ffc5996b180 0x7ffc5996b188 0x7ffc5996b190
Addresses are 0x7ffc5996b1a0 0x7ffc5996b1a8 0x7ffc5996b1b0
Addresses are 0x7ffc5996b1c0 0x7ffc5996b1c8 0x7ffc5996b1d0
24 24 24 24
So for object b, I wonder why I did not get 0x7ffc5996b178 as my address. Why is C++ skipping 8 bytes before starting the next object?
Converting a variety of comments into a Community Wiki answer.
Are the assignments necessary? Does anything change if you use V3(double a, double b, double c) : x(a), y(b), z(c) { cout << …; }? (I don't expect there to be a difference.) Did you try printing the addresses of the class objects in main()? Does that throw any light on things? Ultimately, though, your question is futile — the compiler is allowed to use any layout and alignment it chooses as long as it gives the correct results.
Just a guess: x86 cache lines are 64 bytes. By aligning this way, the first 2 objects would fit in 1 cache line, and the third would fit in a second cache line. If they were not aligned this way, the third object would be split across 2 cache lines which is bad. As already said though, it's not necessarily well-defined.
If compiled using clang on arch the objects are densely packed in memory, when using g++ they are not.
I am working on a chapter review of a book: at the end of the chapter there are some questions/tasks which you are to complete.
I decided to do them in the format of a program rather than a text file:
#include <iostream>
int main(int argc, char* argv[]) {
std::cout << "Chapter review\n"
<< "1. Why does C++ have more than one integer type?\n"
<< "\tTo be able to represent more accurate values & save memory by only allocating what is needed for the task at hand.\n"
<< "2. Declare variables matching the following descriptions:\n"
<< "a.\tA short integer with the value 80:\n";
short myVal1 = 80;
std::cout << "\t\t\"short myVal1 = 80;\": " << myVal1 << std::endl
<< "b.\tAn unsigned int integer with the value 42,110:\n";
unsigned int myVal2 = 42110;
std::cout << "\t\t\"unsigned int myVal2 = 42110;\": " << myVal2 << std::endl
<< "c.\tAn integer with the value 3,000,000,000:\n";
float myVal3 = 3E+9;
std::cout << "\t\t\"float myVal3 = 3E+9;\": " << static_cast<unsigned int>(myVal3) << std::endl
<< "3. What safeguards does C++ provide to keep you from exceeding the limits of an integer type?\n"
<< "\tWhen it reaches maximum number it starts from the begging again (lowest point).\n"
<< "4. What is the distinction between 33L and 33?\n"
<< "\t33L is of type long, 33 is of type int.\n"
<< "5. Consider the two C++ statements that follow:\n\tchar grade = 65;\n\tchar grade = 'A';\nAre they equivalent?\n"
<< "\tYes, the ASCII decimal number for 'A' is '65'.\n"
<< "6. How could you use C++ to find out which character the code 88 represents?\nCome up with at least two ways.\n"
<< "\t1: \"static_cast<char>(88);\": " << static_cast<char>(88) << std::endl; // 1.
char myChar = 88;
std::cout << "\t2: \"char myChar = 88;\": " << myChar << std::endl // 2.
<< "\t3: \"std::cout << (char) 88;\" " << (char) 88 << std::endl // 3.
<< "\t4: \"std::cout << char (88);\": " << char (88) << std::endl // 4.
<< "7. Assigning a long value to a float can result in a rounding error. What about assigning long to double? long long to double?\n"
<< "\tlong -> double: Rounding error.\n\tlong long -> double: Significantly incorrect number and/or rounding error.\n"
<< "8. Evaluate the following expressions as C++ would:\n"
<< "a.\t8 * 9 + 2\n"
<< "\t\tMultiplication (8 * 9 = 72) -> addition (72 + 2 = 74).\n"
<< "b.\t6 * 3 / 4\n"
<< "\t\tMultiplication (6 * 3 = 18 -> division (18 / 4 = 4).\n"
<< "c.\t3 / 4 * 6\n"
<< "\t\tDivision (3 / 4 = 0) -> multiplication (0 * 6 = 0).\n"
<< "d.\t6.0 * 3 / 4\n"
<< "\t\tMultiplication (6.0 * 3 -> 18.0) -> division (18.0 / 4 = 4.5).\n"
<< "e.\t 15 % 4\n"
<< "\t\tDivision (15 / 4 = 3.75) Then returns the reminder, basically how many times can 4 go into 15 in this case that is 3 (3*4 = 12).\n"
<< "9. Suppose x1 and x2 are two type of double variables that you want to add as integers and assign to an integer variable. Construct a C++ statement for doing so. What if you wanted to add them as type double and then convert to int?\n"
<< "\t1: \"int myInt = static_cast<double>(doubleVar);\"\n\t2: \"int myInt = int (doubleVar);\".\n"
<< "10. What is the variable type for each of the following declarations?\n"
<< "a.\t\"auto cars = 15;\"\n\t\tint\n"
<< "b.\t\"auto iou = 150.37f;\"\n\t\tfloat\n"
<< "c.\t\"auto level = 'B';\"\n\t\tchar\n"
<< "d.\t\"auto crat = U'/U00002155';\"\n\t\twchar_t ?\n"
<< "e.\t\"auto fract = 8.25f/.25;\"\n\t\tfloat" << std::endl;
return 0;
}
It's been a while since I read chapter 3 due to moving/some other real life stuff.
What I am unsure about here is basically question number 3: it says safeguards as in plural.
However I am only aware of one: that it starts from the beginning again after reaching maximum value? Am I missing something here?
Let me know if you see any other errors also - I am doing this to learn after all :).
Basically I can't accept a comment as an answer so to sum it up:
There are none safeguards, I misunderstood that question which #n.m. clarified for me.
10.e was wrong as pointed out by #Jarod42, which is correct.
Thanks!
As for me "Declare variable of integer with the value 3,000,000,000" is:
unsigned anInteger = 3000000000;
cause c++ the 11th supplies 15 integer types and unsigned int is the smallest that can store such a big integer as 3 000 000 000.
C++ classifies integer overflow as "Undefined Behavior" - anything can happen as a result of it. This by itself may be called a "safeguard" (though it's a stretch), by the following thinking:
gcc has that -ftrapv compilation switch that makes your program crash when integer overflow happens. This allows you to debug your overflows easily. This feature is possible because C++ made it legal (by nature of Undefined Behavior) to make your program crash in these circumstances. I think the C++ Committee had this exact scenario in mind when making that part of the C++ Standard.
This is different from e.g. Java, where integer overflow causes wraparound, and is probably harder to debug.
I still have not run it through enough tests however for some reason, using certain non-negative values, this function will sometimes pass back a negative value. I have done a lot of manual testing in calculator with different values but I have yet to have it display this same behavior.
I was wondering if someone would take a look at see if I am missing something.
float calcPop(int popRand1, int popRand2, int popRand3, float pERand, float pSRand)
{
return ((((((23000 * popRand1) * popRand2) * pERand) * pSRand) * popRand3) / 8);
}
The variables are all contain randomly generated values:
popRand1: between 1 and 30
popRand2: between 10 and 30
popRand3: between 50 and 100
pSRand: between 1 and 1000
pERand: between 1.0f and 5500.0f which is then multiplied by 0.001f before being passed to the function above
Edit:
Alright so after following the execution a bit more closely it is not the fault of this function directly. It produces an infinitely positive float which then flips negative when I use this code later on:
pPMax = (int)pPStore;
pPStore is a float that holds popCalc's return.
So the question now is, how do I stop the formula from doing this? Testing even with very high values in Calculator has never displayed this behavior. Is there something in how the compiler processes the order of operations that is causing this or are my values simply just going too high?
In this case it seems that when you are converting back to an int after the function returns it is possible that you reach the maximum value of an int, my suggestion is for you to use a type that can represent a greater range of values.
#include <iostream>
#include <limits>
#include <boost/multiprecision/cpp_int.hpp>
int main(int argc, char* argv[])
{
std::cout << "int min: " << std::numeric_limits<int>::min() << std::endl;
std::cout << "int max: " << std::numeric_limits<int>::max() << std::endl;
std::cout << "long min: " << std::numeric_limits<long>::min() << std::endl;
std::cout << "long max: " << std::numeric_limits<long>::max() << std::endl;
std::cout << "long long min: " << std::numeric_limits<long long>::min() << std::endl;
std::cout << "long long max: " << std::numeric_limits<long long>::max() << std::endl;
boost::multiprecision::cpp_int bigint = 113850000000;
int smallint = 113850000000;
std::cout << bigint << std::endl;
std::cout << smallint << std::endl;
std::cin.get();
return 0;
}
As you can see here, there are other types which have a bigger range. If these do not suffice I believe the latest boost version has just the thing for you.
Throw an exception:
if (pPStore > static_cast<float>(INT_MAX)) {
throw std::overflow_error("exceeds integer size");
} else {
pPMax = static_cast<int>(pPStore);
}
or use float instead of int.
When you multiply the maximum values of each term together you get a value around 1.42312e+12 which is somewhat larger than a 32 bit integer can hold, so let's see what the standard has to say about floating point-to-integer conversions, in 4.9/1:
A prvalue of a floating point type can be converted to a prvalue of an
integer type. The conversion trun- cates; that is, the fractional part
is discarded. The behavior is undefined if the truncated value cannot
be represented in the destination type.
So we learn that for a large segment of possible result values your function can generate, the conversion back to a 32 bit integer would be undefined, which includes making negative numbers.
You have a few options here. You could use a 64 bit integer type (long or long long possibly) to hold the value instead of truncating down to int.
Alternately you could scale down the results of your function by a factor of around 1000 or so, to keep the maximal results within the range of values that a 32 bit integer could hold.
I'm using memcpy to copy the content of std:vectors<> to primitve Arrays. For datatypes like int, float, double etc. it worked well. As I started to copy a boolvector I encountered a problem namely I got strange values.
First I started to make an test output for a float vector:
std::vector<float> test1 (3,0);
cout << "Sizeof test1[0] : " << sizeof(test1[0]) << endl
<< "Memoryaddress 0: " << &test1[0] << endl
<< "Memoryaddress 1: " << &test1[1] << endl
<< "Memoryaddress 2: " << &test1[2] << endl;
The output is:
Sizeof test1[0]: 4
Memoryaddress 0: 02793820
Memoryaddress 1: 02793824
Memoryaddress 2: 02793828
And this is what I expect. The float size is 4 Byte and the distance to the next float value is 4 Byte. When I do this for bool the output looks like this:
std::vector<bool> test (3,0);
cout << "Sizeof test[0]: " << sizeof(test[0]) << endl
<< "Memoryaddress 0: " << &test[0] << endl
<< "Memoryaddress 1: " << &test[1] << endl
<< "Memoryaddress 2: " << &test[2] << endl;
The output is:
Sizeof test[0]: 16
Memoryaddress 0: 011EF94C
Memoryaddress 1: 011EF93C
Memoryaddress 2: 011EF92C
Why is the size of bool 16 Byte? It seems like a total overkill to me. Are there explanations for this?
Unlike other specialisations of vector, vector<bool> does not manage a dynamic array of bool objects. Instead, it is supposed to pack the boolean values into a single bit each.
Since individual bits are not addressable, test[0] cannot simply be a reference to bool. Instead, it is an class type vector<bool>::reference that can be converted to bool (to get the value), and assigned from bool (to modify the vector element).
This means that vector<bool> doesn't entirely meet the requirements of a standard container, and can't be used if you need references or pointers to its elements. If you do require a "real" container with addressable elements, consider vector<char> or deque<bool> instead.
std::vector<bool> is a specialized version of vector, which is optimizes for space.
The storage is not necessarily an array of bool values, but the library implementation may optimize storage so that each value is stored in a single bit.
Elements are not constructed using the allocator object, but their value is directly set on the proper bit in the internal storage.
More information: http://www.cplusplus.com/reference/vector/vector-bool/
The application I am working on receives C style structs from an embed system whose code was generated to target a 16 bit processor. The application which speaks with the embedded system is built with either a 32 bit gcc compiler, or a 32 bit MSVC c++ compiler. The communication between the application and the embedded system takes place via UDP packets over ethernet or modem.
The payload within the UDP packets consist of various different C style structs. On the application side a C++ style reinterpret_cast is capable of taking the unsigned byte array and casting it into the appropriate struct.
However, I run into problems with reinterpret_cast when the struct contains enumerated values. The 16 bit Watcom compiler will treat enumerated values as an uint8_t type. However, on the application side the enumerated values are treated as 32 bit values. When I receive a packet with enumerated values in it the data gets garbled because the size of the struct on the application side is larger the struct on the embedded side.
The solution to this problem, so far, has been to change the enumerated type within the struct on the application side to an uint8_t. However, this is not an optimal solution because we can no longer use the member as an enumerated type.
What I am looking for is a solution which will allow me to use a simple cast operation without having to tamper with the struct definition in the source on the application side. By doing so, I can use the struct as is in the upper layers of my application.
As noted, correctly deal with the issue is proper serialization and deserialization.
But it doesn't mean we can't try some hacks.
Option 1:
If you particular compiler support packing the enum (in my case gcc 4.7 in windows), this might work:
typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 }__attribute__ ((__packed__)) TheRealEnum;
Option 2:
If your particular compiler supports class sizes of < 4 bytes, you can use a HackedEnum class which uses operator overloading for the conversion (note the gcc attribute you might not want it):
class HackedEnum
{
private:
uint8_t evalue;
public:
void operator=(const TheRealEnum v) { evalue = v; };
operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));
You would replace TheRealEnum in your structures for HackedEnum, but you still continue using it as TheRealEnum.
A full example to see it working:
#include <iostream>
#include <stddef.h>
using namespace std;
#pragma pack(push, 1)
typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 } TheRealEnum;
typedef struct
{
uint16_t v1;
uint8_t enumValue;
uint16_t v2;
}__attribute__((packed)) ShortStruct;
typedef struct
{
uint16_t v1;
TheRealEnum enumValue;
uint16_t v2;
}__attribute__((packed)) LongStruct;
class HackedEnum
{
private:
uint8_t evalue;
public:
void operator=(const TheRealEnum v) { evalue = v; };
operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));
typedef struct
{
uint16_t v1;
HackedEnum enumValue;
uint16_t v2;
}__attribute__((packed)) HackedStruct;
#pragma pop()
int main(int argc, char **argv)
{
cout << "Sizes: " << endl
<< "TheRealEnum: " << sizeof(TheRealEnum) << endl
<< "ShortStruct: " << sizeof(ShortStruct) << endl
<< "LongStruct: " << sizeof(LongStruct) << endl
<< "HackedStruct: " << sizeof(HackedStruct) << endl;
ShortStruct ss;
cout << "address of ss: " << &ss << " size " << sizeof(ss) <<endl
<< "address of ss.v1: " << (void*)&ss.v1 << endl
<< "address of ss.ev: " << (void*)&ss.enumValue << endl
<< "address of ss.v2: " << (void*)&ss.v2 << endl;
LongStruct ls;
cout << "address of ls: " << &ls << " size " << sizeof(ls) <<endl
<< "address of ls.v1: " << (void*)&ls.v1 << endl
<< "address of ls.ev: " << (void*)&ls.enumValue << endl
<< "address of ls.v2: " << (void*)&ls.v2 << endl;
HackedStruct hs;
cout << "address of hs: " << &hs << " size " << sizeof(hs) <<endl
<< "address of hs.v1: " << (void*)&hs.v1 << endl
<< "address of hs.ev: " << (void*)&hs.enumValue << endl
<< "address of hs.v2: " << (void*)&hs.v2 << endl;
uint8_t buffer[512] = {0};
ShortStruct * short_ptr = (ShortStruct*)buffer;
LongStruct * long_ptr = (LongStruct*)buffer;
HackedStruct * hacked_ptr = (HackedStruct*)buffer;
short_ptr->v1 = 1;
short_ptr->enumValue = VALUE_2;
short_ptr->v2 = 3;
cout << "Values of short: " << endl
<< "v1 = " << short_ptr->v1 << endl
<< "ev = " << (int)short_ptr->enumValue << endl
<< "v2 = " << short_ptr->v2 << endl;
cout << "Values of long: " << endl
<< "v1 = " << long_ptr->v1 << endl
<< "ev = " << long_ptr->enumValue << endl
<< "v2 = " << long_ptr->v2 << endl;
cout << "Values of hacked: " << endl
<< "v1 = " << hacked_ptr->v1 << endl
<< "ev = " << hacked_ptr->enumValue << endl
<< "v2 = " << hacked_ptr->v2 << endl;
HackedStruct hs1, hs2;
// hs1.enumValue = 1; // error, the value is not the wanted enum
hs1.enumValue = VALUE_1;
int a = hs1.enumValue;
TheRealEnum b = hs1.enumValue;
hs2.enumValue = hs1.enumValue;
return 0;
}
The output on my particular system is:
Sizes:
TheRealEnum: 4
ShortStruct: 5
LongStruct: 8
HackedStruct: 5
address of ss: 0x22ff17 size 5
address of ss.v1: 0x22ff17
address of ss.ev: 0x22ff19
address of ss.v2: 0x22ff1a
address of ls: 0x22ff0f size 8
address of ls.v1: 0x22ff0f
address of ls.ev: 0x22ff11
address of ls.v2: 0x22ff15
address of hs: 0x22ff0a size 5
address of hs.v1: 0x22ff0a
address of hs.ev: 0x22ff0c
address of hs.v2: 0x22ff0d
Values of short:
v1 = 1
ev = 2
v2 = 3
Values of long:
v1 = 1
ev = 770
v2 = 0
Values of hacked:
v1 = 1
ev = 2
v2 = 3
On the application side a C++ style reinterpret_cast is capable of taking the unsigned byte array and casting it into the appropriate struct.
The layout of structs is not required to be the same between different implementations. Using reinterpret_cast in this way is not appropriate.
The 16 bit Watcom compiler will treat enumerated values as an uint8_t type. However, on the application side the enumerated values are treated as 32 bit values.
The underlying type of an enum is chosen by the implementation, and is chosen in an implementation defined manner.
This is just one of the many potential differences between implementations that can cause problems with your reinterpret_cast. There are also actual alignment issues if you're not careful, where the data in the received buffer isn't appropriately aligned for the types (e.g., an integer that requires four byte alignment ends up one byte off) which can cause crashes or poor performance. Padding might be different between platforms, fundamental types might have different sizes, endianess can differ, etc.
What I am looking for is a solution which will allow me to use a simple cast operation without having to tamper with the struct definition in the source on the application side. By doing so, I can use the struct as is in the upper layers of my application.
C++11 introduces a new enum syntax that allows you to specify the underlying type. Or you can replace your enums with integral types along with a bunch of predefined constants with manually declared values. This only fixes the problem you're asking about and not any of the other ones you have.
What you should really do is proper serialization and deserialization.
Put your enumerated type inside of a union with a 32-bit number:
union
{
Enumerated val;
uint32_t valAsUint32;
};
This would make the embedded side have it expanded to 32-bit. Should work as long as both platforms are little-endian and the structs are zero-filled initially. This would change wire format, though.
If by "simple cast operation" you mean something that's expressed in the source code, rather than something that's necessarily zero-copy, then you can write two versions of the struct -- one with enums, one with uint8_ts, and a constructor for one from the other that copies it element-by-element to repack it. Then you can use an ordinary type-cast in the rest of the code. Since the data sizes are fundamentally different (unless you use the C++11 features mentioned in another answer), you can't do this without copying things to repack them.
However, if you don't mind some small changes to the struct definition on the application side, there are a couple of options that don't involve dealing with bare uint8_t values. You could use aaronps's answer of a class that is the size of a uint8_t (assuming that's possible with your compiler) and implicitly converts to and from an enum. Alternately, you could store the values as uint8_ts and write some accessor methods for your enum values that take the uint8_t data in the struct and convert it to an enum before returning it.