Hi,
I am using CodeWarrior with a MC9S08QE128 and have found a curious probelm when trying to subtract elements of arrays when they are pointers. Here is a sample of code which reproduces the problem:
const char *const ordinals[]={ "first", "second", "third"};void main(void) { const char *o1p; const char *o2p; int o1len; // I would expect this to assign to o1len the length of the string pointed // to by ordinals[0] o1len=ordinals[1]-ordinals[0]; // This really does assign to o1len the length of the string pointed to by // ordinals[0] o1p=ordinals[0]; o2p=ordinals[1]; o1len=o2p-o1p; ... }
The first subtraction actually assignes a value of 2 to o1len, presumably because it is subtracting the addresses of the elements, rather than their actual pointer values. Here is the listing produced:
ANSI-C/cC++ Compiler for HC08 V-5.0.24 Build 7134, May 15 2007 1: #include <hidef.h> /* for EnableInterrupts macro */ 2: #include "derivative.h" /* include peripheral declarations */ 3: 4: const char *const ordinals[]= 5: { 6: "first", "second", "third" 7: }; 8: 9: void main(void) 10: {Function: main ... 0000 a7fa [2] AIS #-6 11: const char *o1p; 12: const char *o2p; 13: int o1len; 14: 15: // I would expect this to assign to o1len the length of the string pointed 16: // to by ordinals[0] 17: o1len=ordinals[1]-ordinals[0]; 0002 ae02 [2] LDX #2 0004 8c [1] CLRH 0005 9eff05 [5] STHX 5,SP 18: 19: // This really does assign to o1len the length of the string pointed to by 20: // ordinals[0] 21: o1p=ordinals[0]; 0008 320000 [5] LDHX ordinals 000b 9eff01 [5] STHX 1,SP 22: o2p=ordinals[1]; 000e 320002 [5] LDHX ordinals:2 0011 9eff03 [5] STHX 3,SP 23: o1len=o2p-o1p; 0014 95 [2] TSX 0015 e603 [3] LDA 3,X 0017 e001 [3] SUB 1,X 0019 87 [2] PSHA 001a e602 [3] LDA 2,X 001c f2 [3] SBC ,X 001d 87 [2] PSHA 001e 8a [3] PULH 001f 88 [3] PULX 0020 9eff05 [5] STHX 5,SP 24: 25:
The second subtract does what I expected, so I have a solution to this problem, but I do not understand what is wrong with the first case. Am I doing something silly, or is it a compiler bug?
Thanks,
David.
Dear Pyriform,
As you suggest, this does look like a compiler bug to me - or at least an unintentional operation.
Using
o1len=(int)ordinals[1]-(int)ordinals[0];
produces the expected value.
However I believe that pointer arithmetic is only guaranteed to be sensible for pointers into the same object (and one element beyond for arrays). So perhaps this isn't really a bug since the operation you are doing is, strictly speaking, undefined in C. In practice I would also expect it to work as you expected. It is certainly not portable code.
bye
I filed a (internal) bugreport on the initial code snippet. The code is indeed "undefined behavior", but the code the compiler generates is not ok regardless.
Daniel