hi, I'm a C51 beginner,I writen a C51 program which generated binary code about 30Kbytes, but in .asm program,it generated binary code only about 16Kbyte. How can I save the C51 program's code size? thanks!
Are the 2 programs doing the same thing? Or have you used things like printf? Are you an experienced Assembler programmer? If so, you should be able to look at the compiler output and see where the "ineffiency" lies What optimisation setting are you using? In 'C', it is very easy to write very inefficient code! Have you read Appendix C, "Writing Optimum Code" in the C51 manual?
Thanks Andrew Neil !Maybe I should do something like what you said.beside those you had said, what should I pay attention to save my C51 program code size?
You should be prepared for larger code size when using a C compiler, especially since the 8051 is not an ideal target for 'C'. The 8051 architecture was designed at a time when 8K of ROM was considered a lot of program memory. 'C' came out after the 8051, and at the time the only higher level languages were PL/M or Basic for micros. You should optimize for code size rather than speed (see the compiler options), but based on my experience, a 2X increase in code size is not out of line.
When you say the program generate 30K binary code, where are you looking to determine the size of the code? If you are looking at the size of the .OBJ file, you are looking the wrong place. The .OBJ file is not indicative of the size of the code. To find the size of the code, you must look in the .LST file generated by the compiler or the assembler. Jon
Jon is correct, you have to look at the map file from the linker. This is a file with an .M51 extension. One thing that the C51 compiler doesn't optimize well is indexed array access. Since there are no index registers as there are in X86 devices, every time an indexed array is accessed, the address is calculated. Using pointer access will reduce the code and also improve speed by a significant amount. You should also look carefully at the memory model you use, and memory access, as this can also drastically affect code size and speed.
"every time an indexed array is accessed, the address is calculated. Using pointer access will reduce the code and also improve speed by a significant amount." This is not necessarily true! I looked at this in some detail a while ago, and found that adding a pointer may actually use more code and, therefore, be slower! eg,
for (i = n; i != 0; i--) { *bcdP += '0'; ++bcdP; }
for (i = n; i != 0; i--) { bcdP[i] += '0'; }
The 8051 prefered integer size is unsigned 8 bits or unsigned 1 bit. 1)When ever possible use bit then unsigned char, then use char. 2) Use the no integer promote option. This keeps intemediate calculation 8 bits. You might have to change your code to accomadate this. 3) Avoid generic pointers, i.e. always prefer data*, idata*, pdata*, xdata*, or code* over a plain *. 4) If you have the resources, store fequently use variable first in data, then in idata & pdata, and finally in xdata.
I had the unusual experience of taking an application written in assembler and re-coding it in 'C' to the same design. The original assembler was carefully written and needed just over 16K bytes. The 'C' code required some careful work on it to bring the size down, but ended up at just over 24K bytes. I think that must put Keil C in a favourable light – not many compilers would achieve such a small increase in program size. Still, work was required. As Tom points out, memory models are key to getting program size down. I suggest that you should compile with a large default memory model, but specify a memory model for each function (small, compact or large) depending upon how fast and how often it must run. Global variables may also be placed in a specific area of memory. Once your application is building, you can use the source browser to find out which variables are most frequently accessed by your application. To minimise program size (and usual increase speed) these variables should be placed in memory in the following order of preference: data, pdata, xdata. The exception is arrays – these are often too big to justify putting data and are usually best placed in pdata or xdata. Small arrays might be placed in idata. It is well worth getting to know the Source browser - its a very useful tool. In most cases, pre and post decrements should be removed from within statements and placed in separate statements. Generally, the compiled code is small and quicker. The only exceptions to this rule-of-thumb are the following constructs:
unsigned char loop; ... loop = 100; do { // stuff } while ( --loop != 0 );
unsigned char count; ... if (--count != 0 ) { // stuff }
You can also reduce some code, especially PUSH and POP instructions, using the using x keyword. Take a look in the C51 User's Manual for more details. There're also a good piece of code about the using keyword posted here in this forum a couple of months ago.
Andrew was correct. I should have said multiple dimension arrays in my previous posts. This access makes the code recalculate the address in loops, rather than just incrementing a pointer. This usually requires one or more multiplies in the code which usually takes awhile. He makes an excellent point that you really need to look at the assembler code that results when you are trying to optimize execution speed or size.