1

This is for MPLABXC8 compiler I have researched and found number of topics related. But not able to solve my issue. My Array typedef

     typedef volatile struct OneStageOpTag
   {
        unsigned DevID1: 4;
        unsigned SetCmd1 : 4;
        unsigned RdyResponse1 :4;
        unsigned DevID2: 4;
        unsigned SetCmd2 : 4;
        unsigned RdyResponse2 :4;
        unsigned DevID3: 4;
        unsigned SetCmd3 : 4;
        unsigned RdyResponse3 :4;
    }OneStageOpType[3];

Now my variable

    OneStageOpType CurOperPlan={0};// I checked this one - 
        //-in Simulator 3 element array of structure created

Now I am passing pointer to my function

GetOperationSeqForTransportReq(1,1,&CurOperPlan);

below is the function

void GetOperationSeqForTransportReq(StationIDType SourseStnID,StationIDType DestiStnID,
                    OneStageOpType  *CurTransportPlan)
{
    NOP();
    CurTransportPlan[0]->DevID1=5;  // This is Ok
    CurTransportPlan[1]->DevID1=5;  // This is Not working      
}

only the 0th element is accessable. Also compiler complaints that structure pointer passed to structure array pointer. I tried by incrimenting the pointer in function. It seems incrimenting the whole Array pointer. It seems to me that &CurOperPlan is adress pointer to 0th index structure only. The whole array is not contained it. please help.

8
  • 3
    Start by not typedeffing arrays. Commented Mar 26, 2016 at 6:16
  • Remember that the array itself is a pointer. You are dereferencing a pointer (the array) here: GetOperationSeqForTransportReq(1,1,&CurOperPlan); either use GetOperationSeqForTransportReq(1,1,CurOperPlan); or (*CurTransportPlan)[0]->DevID1=5; with the type OneStageOpTag *. Commented Mar 26, 2016 at 6:16
  • 1
    As @ThomasPadron-McCarthy pointed out - your code took a wrong turn the moment you typedefed an array. Commented Mar 26, 2016 at 6:18
  • This code is a part of this thread stackoverflow.com/questions/36214847/… I am using that typedef to create a two dimentional array in ROM. Not able to find another way. Commented Mar 26, 2016 at 6:19
  • 2
    @Myst: "Remember that the array itself is a pointer" no, it isn't really. And array just decays to a pointer to its 1st element under certain conditions, for example it does when getting passed to a function. Commented Mar 26, 2016 at 8:13

3 Answers 3

3

Change this

GetOperationSeqForTransportReq(1,1,&CurOperPlan);

to be

GetOperationSeqForTransportReq(1, 1, CurOperPlan);

and this

void GetOperationSeqForTransportReq(StationIDType SourseStnID,StationIDType DestiStnID,
                OneStageOpType  *CurTransportPlan)

to be this

void GetOperationSeqForTransportReq(
  StationIDType SourseStnID,
  StationIDType DestiStnID,
  OneStageOpType CurTransportPlan)

For completeness also change this

OneStageOpType CurOperPlan={0};

to be

OneStageOpType CurOperPlan = {{0}};
Sign up to request clarification or add additional context in comments.

2 Comments

{0} is a correct idiom to zero-initialize an aggregate in all cases. IMHO sticking to common idioms is not a bad idea. There were some earlier versions of gcc that warned about incomplete bracing for {0} but I believe they have been updated now to not give that bogus warning.
@M.M: "they have been updated now to not give that bogus warning" Really? Great! :-) I perhaps should update though ... :}
1

Inside the function, you need:

(*CurTransportPlan)[0].DevID1=5;  // This is Ok
(*CurTransportPlan)[1].DevID1=5;

This is because CurTransportPlan is a pointer to your array. So you must dereference it to get the array. Then you can apply array indexing to the array.

Link to working example


To explain why the first one seemed to work, we can rewrite the code applying the equivalence transformations X->Y = (*X).Y, and X[N] = *(X+N).

The correct indexing in array notation should be CurTransportPlan[0][0].DevID1 and CurTransportPlan[0][1].DevID1 ; however your code swapped the indices in both cases. This meant the first one still worked but the second one broke.


Regarding your code design: it's been noted that there are two ways to approach passing an array to a function:

  1. You can pass a pointer to the first element of the array, as alk suggests (passing the length separately, or hard-coding it)

  2. You can pass a pointer to the entire array as you are currently doing.

I will list some of the differences between these two designs. Using your design, i.e. the pointer-to-whole-array:

  • You get a compilation error if an array with a different number of rows is passed.
  • You get a compilation error if a non-volatile array is passed.
  • You must write (*ptr) instead of ptr, which is slightly more verbose.

The decision for you to make is whether you want the compiler to give errors in those first two points. The errors can be avoided by casting, but generally speaking, need to cast is a sign that the other approach would have been a better design.

If this function is only ever to be used with the size-3 volatile array then IMHO your current approach is the best one, invoking maximum compiler detection of errors.

9 Comments

Agreed, however I do not think the OP intended to actually implement this additional indirection.
Nice :-) - one may add, that for the 2nd design it also is possible to change the value being passed in "by reference" inside the function.
(*CurTransportPlan)[0].DevID1=5; (*CurTransportPlan)[1].DevID1=5; This i not compiling in my case Error [209] D:\UB_Wrks\PLC_Dmain\PTS_Shammy\Firmware\BlowerUnit\PTS_BlowerUnit.X\PTS_DataSetModule.c; 28.22 type conflict Error [981] D:\UB_Wrks\PLC_Dmain\PTS_Shammy\Firmware\BlowerUnit\PTS_BlowerUnit.X\PTS_DataSetModule.c; 28.23 pointer required Error [981] D:\UB_Wrks\PLC_Dmain\PTS_Shammy\Firmware\BlowerUnit\PTS_BlowerUnit.X\PTS_DataSetModule.c; 28.23 pointer required (908) exit status = 1
@user2454516 I included link to working example in the first part of my answer, compare your code with that to see if you made a typo somewhere. I guess maybe you removed * as an earlier answer suggested, but didn't put it back when trying mine out
@MM. Sorry for the mistake before .the code is working. Now I am testing two approaches. One is passing the element and incrimenting the pointer to get the next index. Seems ok. In the calliing argument compiler (MPLAB XC8 is not making any complaints if I use "CurOperPlan or &CurOperPlan" it works. But When I use the passing array as the argument method, I am getting data loaded correctly wuth your method (*CurTransportPlan)[0].DevID1=5; // This is Ok But compiler complains about illegal pointer conversion in the calling line if I use & or without.
|
-1

As you have a typedef of three elements array:

typedef volatile struct OneStageOpTag {
  // ...
} OneStageOpType[3];

The problem looks to be:

void GetOperationSeqForTransportReq(
  StationIDType SourseStnID,
  StationIDType DestiStnID,
  OneStageOpType *CurTransportPlan)       // HERE

In above function you are declaring parameter as a pointer to 3-element array, but you should pass it as a pointer to first element of array. This means you should do the following instead:

typedef volatile struct _OneStageOpTag {
  // ...
} Array[3], Element;

// ...

Array CurOperPlan={0};
GetOperationSeqForTransportReq(1,1,&CurOperPlan);

// ...

void GetOperationSeqForTransportReq(StationIDType SourseStnID,
  StationIDType DestiStnID, Element *CurTransportPlan)
{
  NOP();
  CurTransportPlan[0]->DevID1=5;  // This is Ok
  CurTransportPlan[1]->DevID1=5;  // This is Not working      
}

This should works fine for you :)

5 Comments

Thanks. It is working, but with slight diffference. since "CurTransportPlan" is now a pointer to a element, [0] or [1] is not possible. CurTransportPlan->DevID1=5;// this works and then Incriment the pointer CurTransportPlan++; CurTransportPlan->DevID1=6;// this now modifies the [1] element. Only thing array is available as seperate elements in this case. Thanks for the help
Passing &CurOperPlan is not correct as it evaluates to a pointer to the array itself, but what you want is a pointer to its fist element, so just pass CurOperPlan. The compiler should warn about this. Any ways the code might still work as the value of the address of an array is always the same as the value of the address of the array's 1st element ...
Passing a pointer to the element and then incrimenting this pointer to get the other two elements seems working alright. CurOperPlan or &CurOperPlan is not making any practical difference when element is being used. So it seems. But in any case when I pass CurOperPlan or &CurOperPlan, the indexing is not available in the destination function. Thanks
@user2454516 one of the two cases would give a compiler error or warning (note: any such "warning" is actually an error). You should make sure you have a clean compile with no errors or warnings before running the code.
as far as I can understand "&CurOperPlan" is the address of the Array and "CurOperPlan" is the address of the first element of this array. But whern I can passing "&CurOperPlan" as the address of array , still compiler complains. This is when the receiving function expects the pointer at array. If receiving side expects a pinter to the element of this array compiler is happy with both methods. Any Clue?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.