Another small question

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
User avatar
Zedtho
Posts: 189
Joined: February 14th, 2017, 7:32 pm

Another small question

Post by Zedtho » June 27th, 2017, 6:32 am

Sorry for spamming the forum with questions by the way!

When one declares an integer, then you can also put tags on it like 'const' and 'constexpr' and so on.
From my previous post I was able to conclude that the tags are probably not in the form of boolean values, so not like this:

Code: Select all

class int
{
///Obviously not how ints are really stored
bool const = false;
bool constexpr = false;
//...
int;
}
But then how are they stored? I'm currently guessing the compiler makes special spots for them that are marked as const/constexpr/... I hope my question is clear by now, if not please tell me it isn't and I'll clarify.

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: Another small question

Post by cyboryxmen » June 27th, 2017, 7:32 am

C++ programs are standardised to store their variables based on their "storage specification". auto storage(not to be mistaken with the keyword auto) is the default storage specification. These variables are written in function parameters and code blocks and are created "automatically" when the cpu runs the line of code they are in. These variables will be "stacked" onto other previous variables and then removed from the stack once they go out of scope.

Then there are the static variables. These variables would be created at the start of the program and will remain there indefinitely. They would also usually be stored at the start of the stack so the cpu can easily know where they are. Your static const variables and your c-strings would additionally be stored at the "read-only" static memory that are only going to be set once and never be changed again.

Now const and constexpr variables are not implicitly static and are usually(occasionally(sometimes(probably))) set to auto storage instead of being stored in the read only section that I mentioned. This is partly based on whether their values can be determined at the start of the program as opposed to when they are determined after the user gives them a value etc. Now this won't be a factor for constexpr but it may still won't be made static because of C++ specifications saying that the compiler is required to arrange memory according to how the user specifies it. Because of this, it is a good idea to declare your const and constexpr variables static if static storage is what you want them to be stored as.

However, there are also things like inline that basically makes it such that the variable doesn't even exist! The compiler can "inline" the variable into the code making the variable part of the code itself. So instead of function add() using the values of x and y to do addition, the compiler just gets rid of those values and just writes them directly into the code itself. In that case, the values would be stored not on the stack but in the code section of the program. This only works if the compiler can determine what the value of the variable is which is always the case with constexpr. However, if you at any point ask for the address of the variable(pass by reference etc.), the compiler can't inline it since it is forced to exist on the stack.
Zekilk

User avatar
Zedtho
Posts: 189
Joined: February 14th, 2017, 7:32 pm

Re: Another small question

Post by Zedtho » June 27th, 2017, 9:15 am

Thanks a lot for that detailed answer!

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Another small question

Post by albinopapa » June 27th, 2017, 9:21 am

I'd like to add that constexpr in C++11/14 are evaluated at compile time and the compiler will usually replace that variable with the literal of the constexpr.

Writing:

Code: Select all

constexpr int num = 8;
constexpr int num2 = 16;
constexpr int result = num + num2;

The compiler would just do the calculations during compilation and anytime you used 'result' the compiler would replace it with the number 24 so no memory stored and no runtime calculations done. I use this when working with PI.

constexpr float pi = 3.141592f;
constexpr float radian = pi / 180.f;
constexpr float degree = 180.f / pi;

Now to convert degrees to radians, I just multiply the angle in degrees by radian before passing to the sin/cos functions.

You can also have a constexpr array, and I'm pretty sure it gets stuck in the static read-only memory as cyboryxmen says.

Code: Select all

	constexpr float n1 = farray[ 0 ];
	constexpr float n2 = farray[ 1 ];
	constexpr float n3 = farray[ 2 ];
	constexpr float n4 = farray[ 3 ];
	constexpr float n5 = farray[ 4 ];
	constexpr float n6 = pi;
	constexpr float n7 = radian;
	constexpr float n8 = degree;

	PrintNumber( n1 );
	PrintNumber( n2 );
	PrintNumber( n3 );
	PrintNumber( n4 );
	PrintNumber( n5 );
	PrintNumber( n6 );
	PrintNumber( n7 );
	PrintNumber( n8 );
Here's a snippet from the debugger:

Code: Select all

	constexpr float n1 = farray[ 0 ];
	constexpr float n2 = farray[ 1 ];
	constexpr float n3 = farray[ 2 ];
	constexpr float n4 = farray[ 3 ];
	constexpr float n5 = farray[ 4 ];
	constexpr float n6 = pi;
	constexpr float n7 = radian;
	constexpr float n8 = degree;

	PrintNumber( n1 );
00007FF7ADC711B7  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n2 );
00007FF7ADC711BC  movss       xmm0,dword ptr [__real@3ec90fd8 (07FF7ADC73380h)]  
	PrintNumber( n2 );
00007FF7ADC711C4  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n3 );
00007FF7ADC711C9  movss       xmm0,dword ptr [__real@3f490fd8 (07FF7ADC73384h)]  
00007FF7ADC711D1  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n4 );
00007FF7ADC711D6  movss       xmm0,dword ptr [__real@3f96cbe2 (07FF7ADC73388h)]  
00007FF7ADC711DE  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n5 );
00007FF7ADC711E3  movss       xmm0,dword ptr [__real@3fc90fd8 (07FF7ADC7338Ch)]  
00007FF7ADC711EB  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n6 );
00007FF7ADC711F0  movss       xmm0,dword ptr [__real@40490fd8 (07FF7ADC73390h)]  
00007FF7ADC711F8  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n7 );
00007FF7ADC711FD  movss       xmm0,dword ptr [__real@3c8efa33 (07FF7ADC7337Ch)]  
00007FF7ADC71205  call        PrintNumber (07FF7ADC71100h)  
	PrintNumber( n8 );
00007FF7ADC7120A  movss       xmm0,dword ptr [__real@42652ee4 (07FF7ADC73394h)]  
00007FF7ADC71212  call        PrintNumber (07FF7ADC71100h)  
Everywhere you see __real@ and some hex number, it's the floating point number, the hex number in parentheses is the address of that number. If I were to use ints instead of floats, I'm sure it would look different. The compiler is using SSE registers, so the constexpr values are being copied to those registers then sent to my PrintNumber.

By default in VS the first four floats are passed using SSE registers after that it depends on if you compile in x86 or x64, but generally they do get stored/passed using the stack.

Here's a constexpr int array

Code: Select all

constexpr int iarray[] =
{
	1, 3, 5, 7, 11, 13, 17
};
And here's the debugger info

Code: Select all

	PrintNumber( iarray[ 0 ] );
00007FF7A0871187  mov         ecx,1  
00007FF7A087118C  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 1 ] );
00007FF7A0871191  mov         ecx,3  
	PrintNumber( iarray[ 1 ] );
00007FF7A0871196  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 2 ] );
00007FF7A087119B  mov         ecx,5  
00007FF7A08711A0  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 3 ] );
00007FF7A08711A5  mov         ecx,7  
00007FF7A08711AA  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 4 ] );
00007FF7A08711AF  mov         ecx,0Bh  
00007FF7A08711B4  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 5 ] );
00007FF7A08711B9  mov         ecx,0Dh  
00007FF7A08711BE  call        PrintNumber<int> (07FF7A0871FB0h)  
	PrintNumber( iarray[ 6 ] );
00007FF7A08711C3  mov         ecx,11h  
00007FF7A08711C8  call        PrintNumber<int> (07FF7A0871FB0h)  
As you can see, accessing the elements of the constexpr int array, just replaced the variable with the actual number in the array at that index.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
Zedtho
Posts: 189
Joined: February 14th, 2017, 7:32 pm

Re: Another small question

Post by Zedtho » June 27th, 2017, 9:29 am

I remember reading that the compiler will simplify stuff when possible. That definitely does simplify a lot :O. Again, thanks a lot to you guys for answering the questions :D.

Post Reply