Hi, does anyone know if Keil has added support for calls through a function pointer table, or if they are about to do so? Right now it is a bomb, especially when using banked memory. /Christian
The sheer number of variables is a problem only if function pointers are used irresponsibly, without following the docs closely. The real problem is that you have to use function pointers in a disciplined fashion, so you can tell the linker what exactly that fashion looks like. It's lack of this discipline that kills projects. Even with this complication, function pointers IMHO beat most alternatives hands-down for the typical use cases, like a state machine implemented by calls to "transition" functions found in the state table, or cooperative multi-tasking systems where each task is one function. It's a classic case of "sharp knife syndrom". The same thing that would be a public menace in the hands of the clueless is an indispensable tool if wielded by a surgeon.
"The real problem is that you have to use function pointers in a disciplined fashion, so you can tell the linker what exactly that fashion looks like. It's lack of this discipline that kills projects." In fact, there are certain cases where the Linker can deduce the call tree itself - but, again, you have to play strictly by the rules. See the above-mentioned documents for details. "... function pointers IMHO beat most alternatives hands-down for the typical use cases, like a state machine ... " Absolutely! http://www.8052.com/forum/read.phtml?id=47543 http://www.8052.com/forum/read.phtml?id=47549 "It's a classic case of 'sharp knife syndrome'" Definitely!
Running the risk of getting flamed for poor style here, let me run this one by you. I recently used function pointers in a program for (I think) good reason, but in a manner where the call tree was deduced properly. It seems as long as the name of the function pointed to appears in the function it's being called from then the call tree is constructed correctly. My problem was this: I have a product that has to read data from a sensor. We made a modification to the hardware that required using different pins to read this sensor in newer revision boards. So, I read a hardware revision code from the board (usual resistor code, etc.) and want to use the appropriate lines based on that. I have a function, let's call it "GetValue" that performs several reads of the sensor and returns an average value. I also have two functions sensor_read_old and sensor_read_new that read an individual value from the sensor, using either the old or new set of data lines. So, at this point I have a few options. One is to write two separate GetValue functions--one for each sensor acquisition function. The other is to do a comparison within GetValue before every sensor acquisition and call the correct function. This seemed wasteful to me, so I used a function pointer within GetValue and at the top did something like.
unsigned short (* sensorreadfunc)(void); if (hwrev > someval) sensorreadfunc = sensor_read_new; else sensorreadfunc = sensor_read_old;
So long as the Linker can tell at Link time what calls what, you're safe; If the Linker can't tell for itself, but you can, you can be safe - but it's all on your head; If it's all entirely run-time dependent, you're doomed - you will either have to disable all overlaying, or make your functions reentrant (but if that's OK in your application - there's no problem!)
What a thread I have started ;-) I can see that others have had the same problem as I, but some don't seem to really understand the problem. Sentences like "If you had taken even a cursory look into the manual before posting here" only tells me that either the problem hasn't been understood or the solution hasn't been deducted... (I am probably going to hear for this... or killed...) It doesn't get better at all when I read: "Why, oh why, does so many insist on coding the '51 as if it was a "mini PC"?." Now, I wont go into the term "PC" and what it actually stands for, as it goes without saying. Let us just say that in colloquial English the term is used and even more mis-used... To cut things a little clearer. The problem is with the creation of the function calling tree (as I see it). Yes, there are some limitations to the use of function pointers (which the compiler/linker should be able to warn you about if you try to exceed the limits.) for the 8051, but I see no reason to why it should pose such a problem to use them. Let me explain. Right now the Keil compiler 'prefers' to handle all functions/subtrees called through a function pointer table as reentrant or not overlayed. If you either setting things work fine, but your RAM consumption EXPLODES even though it need not to. From one of the Keil notes we have: "When you use a function pointer, the linker cannot correctly create a call tree for your program" My question is why? Why, why, why doesn't the Keil compiler analyze all subtrees, even though called through a function pointer? It is the linker that looks up all cross-references and does the final allocation of data (overlaying). The linker knows whereto the function pointers point, so why doesn't it construct a function calling tree to optimize data overlaying? It has all the information it needs! That is the real question! If two subtrees do not connect to each other, then overlaying is obvious. Other compilers do this so why not Keil? Ok, I am compiling for a different target, but the problem and complexity is the same for all targets. That being a Z80, 8051, AVR, ARM or Pentium for that matter. It is just a matter of what the limitations are.
Why, why, why doesn't the Keil compiler analyze all subtrees, even though called through a function pointer? Because you're underestimating the scope of the problem. Static call tree analysis of a C program involving function pointers is, ultimately, an impossible mission, because of the Halting Problem --- you would have to be able to predict the complete behaviour of the program (and all its inputs, i.e. The World), to know for certain which possible call paths will actually be taken, and which won't. So at some point, the tools just have to give up trying. There might be some truth in your claim that Keil have given up a tad bit early. The "function pointer tables in code space" trick is IMHO a very useful extension of the realm of correctly analyzed usages of function pointers. It covers the majority of cases where function pointers provide enough benefit to outweigh the problems they create. OTOH the 8051 platform is quite severely limited itself, so enormous efforts spent on allowing limitless use of function pointers would arguably be a bad use of Keil's time and your money.
It doesn't get better at all when I read: "Why, oh why, does so many insist on coding the '51 as if it was a "mini PC"?." My question is why? Why, why, why doesn't the Keil compiler analyze all subtrees, even though called through a function pointer? Ok, I am compiling for a different target, but the problem and complexity is the same for all targets. That being a Z80, 8051, AVR, ARM or Pentium for that matter. It is just a matter of what the limitations are. OK, I'll rephrase, your question is "why does Keil not make the '51 behave in a way the architecture were never designed for" You are asking Keil to make software that changes the hardware. You can overcome your problem by switching to a less efficient common base compiler which use the traditional C method of transferring variables on the stack, instead of gaining magnitudes of efficiency by adapting to the unique architecture of the '51 by overlaying. By doing so you will lose some advantages, but your beloved function pointers will be possible. If you want to use the '51 do not complain that it is what it is. Erik
No, I has nothing to do with hardware what so ever. And yes the 8051 wasn't designed with complex calling in mind, but that is not saying that you can't! What I am talking about is purely compiler related. Please make no mistake about that. Forget about target type - it has no meaning here. We have compiler 'A' from company 'A-soft'. Can you make a compiler that can handle function trees through function pointers? The answer is without question yes! Are there limitations depeding on target? The answer is again yes. Does this mean that function pointer utilization and data overlaying is not possible? The answer is no! True, the 8051 has a very noticable limit, but the compiler can easily use X-stack for parameters and thereby overcome much of the limitations. Don't narrow your sigth by looking at hardware restrictions. Look forward and investigate how you can overcome obstacles. If everybody said 'that is impossible' then we would get no where. There isn't anything you can't do with the 8051, as long as you don't exceed the memory limits. The Keil compiler is VERY EFFICIENT when it comes to generate efficient code for the 8051 (I have never questioned this), so I think that it is a shame that it can't go all the way. It is tad annoying that you have to take different compiler capabilities into consideration when writing code, when they all should be able to handle the same code. /Christian
The Keil compiler is VERY EFFICIENT when it comes to generate efficient code for the 8051 (I have never questioned this), so I think that it is a shame that it can't go all the way. EXACTLY and the price for the efficieny is that function calls becomes "troublesome". When there is a tradeoff some will always disagree with the decision. All I am saying is that if you do not like the tradeoff Keihas made, get another compiler. It is tad annoying that you have to take different compiler capabilities into consideration when writing code, when they all should be able to handle the same code. That statement is, in my opinionn, pure and unadulterated bullshit. That would mean that Keil '51 should not have a bit variable because Visual C does not. Erik
Sigh! I thought that it was pretty obvious that we were taking about standard C code and not specific compiler instructions as 'Setbit', which refers directly to assembler instructions. What you are saying is almost like: "the compiler doesn't need to handle switch-case statements as it handles if-else more effieciently". And that doesn't make sense. I am not talking about making trade-offs with the existing Keil optimizations but to add some extra functionality that will improve handling of function pointers in a Keil environment. Forget about it. I don't think you understand what I am talking about.
Forget about it. I don't think you understand what I am talking about. Oh yes, I do. Erik
Can you make a compiler that can handle function trees through function pointers? The answer is without question yes! Perhaps yes when the pointer table has constant values, but if the function pointers are 'dynamic', I think probably not practically.
Yes, that is right. Dynamic function pointers are impossible to work with (optimization wise). But for static pointers it should be. Thanks to you Hans-Bernhard for a very detailed reply. You know what you are talking about /Christian
"Forget about it. I don't think you understand what I am talking about." "Oh yes, I do." No, you only think you do, but you're so wrapped up in one of your favourite rants that you haven't noticed yet that you don't. I suggest you take the time to read the thread carefully.