Do function pointers suffer from the same aliasing problems as normal pointers?
I mean, suppose you use qsort and pass it a function pointer, will it get reloaded again whenever the function is used?
Do function pointers suffer from the same aliasing problems as normal pointers?
I mean, suppose you use qsort and pass it a function pointer, will it get reloaded again whenever the function is used?
What do you mean "reloaded"? Will what get "reloaded"?
Quzah.
Hope is the first step on the road to disappointment.
first a standard "restrict" example:
you have a function with two pointer parameters
void Func(int *a, int *b, int n)
{
for ( int i = 0; i < n; i++)
{
*a += *b;
a++;
}
}
because b might be an alias to some address within a b gets reloaded every time in the loop. That's why restrict is introduced.
But you probably knew that already so now on to the function pointer example:
int MyCompare(const void *pv1, const void *pv2) { ... }
void Func(int (*func)(const void*, const void*))
{
for (...)
(*func)(x, y);
}
Can the compiler assume that the value of the function pointer "func" won't change or will the value be reloaded every time the function pointer is dereferenced?
I hope I'm clear
Well a pointer is a pointer. As such, you can have an array of function pointers, and "walk" down the array, calling function after function...
Quzah.
Hope is the first step on the road to disappointment.
I have never heard of pointers being reloaded. I am pretty sure that they are not. If you would want to make sure that they are not changed, use some protection on it, like a semaphore. Where did you get information that pointers are reloaded in case they change. Pointers just store a number, so if that number were to change it wouldn't matter because the dereference looks at that number, there is no need to reload.
Help populate a c/c++ help irc channel
server: irc://irc.efnet.net
channel: #c
I do not know what the original poster is asking, either.
I think he may be confused.
There is a restrict type qualifier for C99, it's use is limited to pointers. For example, you will see it in the memcpy() prototype:
By qualifying str1 and str2 with restrict, the prototype asserts that the two arguments point to non-overlapping objects, as I understand it.Code:void *memcpy(void *restrict str1, const void * restrict str2, size_t size);
I haven't seen anything about reloading pointers anywhere, not in discussions of restrict in any of the stuff I have. Always interested to see if there's something I missed.
What I think he is saying is that:
can't safely be optimised [edit]by the compiler[/edit] to the potentially faster:Code:void Func(int *a, int *b, int n) { for ( int i = 0; i < n; i++) { *a += *b; a++; } }
because int* b may point to a location in the array pointed to by int* a. Therefore, b must be reloaded at every use. Assumably, the restrict keyword allows this optimization by telling the compiler that int* b and int* a can not overlap.Code:void Func(int *a, int *b, int n) { register int temp = *b; for ( int i = 0; i < n; i++) { *a += temp; a++; } }
What I think he could be asking, is does the same thing apply with function pointers. That is, can this:
be optimised with something like this pseudo-code:Code:void Func(int (*func)(const void*, const void*)) { for (...) (*func)(x, y); }
or does func need to be run from its original location each time in case the code is changed through another pointer.Code:void Func(int (*func)(const void*, const void*)) { processorCachePtr temp = CopyFuncFromSlowRam(func); for (...) (*temp)(x, y); }
This is all totally processor/OS/implementation/optimisation level/code specific.
>> Can the compiler assume that the value of the function pointer "func" won't change or will the value be reloaded every time the function pointer is dereferenced? <<
Yes, it can assume the value of func won't change in this case. If func equals 0x3212 on entry, it will stay with that value. What it may not always be able to assume is that the code that func points to will remain constant. However, this is something that could potentially be determined at compile time:
In this case the compiler could possibly determine that the code for my_function can not change.Code:my_function(const void*, const void*); Func(my_function);
In this case the compiler could possibly determine that the code for my_function can change.Code:FUNC_PTR my_function = VirtualAlloc(NULL, 200, MEM_COMMIT, PAGE_EXECUTE_READWRITE); Func(my_function);
If this post has confused you, don't worry, it has confused me more.
Last edited by anonytmouse; 06-25-2004 at 08:58 PM.
I know that you can't use the &(address of) operator on registers. So code with pointers defined as registers would be dangerous.
Last edited by linuxdude; 06-25-2004 at 08:46 PM.
The register keyword doesn't even ensure that the variable is put in a register. It's basicly a worthless keyword now days, because your compiler optimizes as it sees fit. IIRC, you cannot force it to be a register. It's just a suggestion.
However, as long as you don't need the address of a pointer, I suppose it could work in a register. You wouldn't want to try to assign the address of say your loop counter to a pointer though, had you attempted to make that a register.
But really, there isn't much need for register any more.
Quzah.
Hope is the first step on the road to disappointment.
A function pointer is always loaded each and every time. Actual functions entry points, on the other hand, are traditionally constant, read-only memory locations and thus intrinsically alais-proof, (VirtualAlloc() is an indeed an exception, but then notice it's absence from XP too!).Originally Posted by Laserve
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
>> (VirtualAlloc() is an indeed an exception, but then notice it's absence from XP too!). <<
?? Reports of VirtualAlloc()'s death seem to have been greatly exaggerated.
Currently, you can manipulate code in malloc() memory or even on the stack. However, in the future code will have to run from memory specifically marked with the EXECUTE permission(so as to lessen problems with buffer overruns), hence the use of VirtualAlloc() in my sample.
Hmm, I seem to have read that they were removing it from all future API's - maybe was wrong. Seems a little foolish though to continue supporting it, and if they do that's their own damn fault!
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
>> Seems a little foolish though to continue supporting it, and if they do that's their own damn fault! <<
I assume you mean the ability to manipulate code at run-time rather than VirtualAlloc() itself which being the core user mode memory allocation function(along with the Ex version), has many other essential uses. Why do you think run-time code generation should not be allowed? What about run-time code generation by the .net or Java run times? What about thunking?
http://msdn.microsoft.com/security/p.../exec_imp.aspx
>> ...rather than VirtualAlloc() itself which being the core user mode memory allocation function...
Sorry, I was confusing the function with VirtualProtect().
>> Why do you think run-time code generation should not be allowed?
There is always some level of vunerability exposed with these sort of facilities - when you're trying to secure a system for instance, that can become a real concern.
>> What about run-time code generation by the .net or Java run times?
These are closely scrutinized frameworks that (supposedly) implement tightly-controled mechanisms for code generation.
>> What about thunking?
The ability to implement system-wide execution analysis and redirection is of course extremely useful, it too has it's vunerabilities as well.
I don't mean to imply that there is something inherently wrong about having access to those kinds of services - just that they introduce a level of insecurity that can't be ignored either.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }