0

As the title suggests, when I declare structure BasicSetup_S globally, I get a segmentation fault. But if I move BasicSetup_S into CallFunction() the segmentation fault goes away.

The output is correct each time. It produces exactly what I expect to see but I get the segmentation fault. But, if I move the BasicSetup_S structure inside CallFunction the segmentation fault goes away. Is there any reason why?

I'm thinking that my entire program may use too much memory causing a fault when I declare more global variables.

For ease of reading, I simplified the names of everything and showed only the useful parts of the code

#include <stdio.h>
#include "stdint.h"

typedef struct BasicSetup
{
    uint16_t A;
    uint16_t B;
    uint16_t C;
    uint16_t D;
    uint16_t E;
    uint16_t F[3];
    uint16_t G[7];
}BasicSetup;

BasicSetup BasicSetup_S = {
    // A,               // B,
    1,                  2,
    // C,               // D,
    3,                  4,
    // E,               // F[2],[1],[0]
    5,                    6 , 7 , 8,
    // G[6],[5],[4],[3],[2],[1],[0]
    9 , 10, 11, 12, 13, 14, 15,
};

void CallFunction(uint8_t *writeBuffer, int begAddress, int endAddress)
{
    int i;
    uint16_t tempVal;
    int StartingPoint = 0;

    for (i = begAddress; i < endAddress; i++)
    {
        // Grabs information from Device Information Structure
        if (i >= 0 && i <= 7)
        {
            // Grab Value
            tempVal = *((uint16_t*)&BasicSetup_S.A + i);
            // Send Value
            writeBuffer[(StartingPoint)++] = tempVal & 0xFF;
        }
        else if (i >= 13 && i <= 19)
        {
            // Grab Value
            tempVal = *((uint16_t*)&BasicSetup_S.G + i - 13);
            // Send Value
            writeBuffer[(StartingPoint)++] = tempVal & 0xFF;
        }
    }

    return;
}

int main(int argc, char *argv[]) {
    int numOfBytes = 0;
    int i = 0;
    uint8_t writeBuffer[256];

    CallFunction(writeBuffer, 0, 8);
    for (i = 0; i < 8; i++) printf("%d, ", writeBuffer[i]);
    printf("\n");

    CallFunction(writeBuffer, 13, 19);
    for (i = 0; i < 6; i++) printf("%d, ", writeBuffer[i]);
    printf("\n");

    CallFunction(writeBuffer, 19, 20);
    for (i = 0; i < 1; i++) printf("%d, ", writeBuffer[i]);
    printf("\n");

    return 0;
}
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Rayaarito
  • 400
  • 4
  • 21

1 Answers1

1

The behaviour of your code is undefined.

You cannot use pointer arithmetic (of non-unsigned char type) to reach other scalar members in a struct. For staters, you are assuming there is no padding between the members.

Why not use a single array instead?

typedef struct BasicSetup
{
    uint16_t m[15];
} BasicSetup;

The C standard insists that the array data are contiguous, and pointer arithmetic is then perfectly well-defined.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • "You cannot use pointer arithmetic to reach other scalar members in a struct" Sure you can, this is perfectly fine, although there might be padding anywhere. There is no UB, given that all access is aligned. – Lundin Dec 11 '17 at 14:12
  • @Lundin. No, you can't. You can take the address of a scalar, or set a pointer one beyond it. But you can't dereference a pointer obtained in the latter manner. What makes you think otherwise? – Bathsheba Dec 11 '17 at 14:15
  • @Lundin not again. Of course there is UB because the standard says so. – Antti Haapala -- Слава Україні Dec 11 '17 at 14:16
  • Bathsheba is right, @Lundin. Pointer arithmetic is defined only within the array into which the pointer points, with scalars treated as one-element arrays, and with the exception that a pointer to the element just past the end of the array can be computed (but not dereferenced). – John Bollinger Dec 11 '17 at 14:16
  • What I mean is this `for(uint8_t* ptr = (uint8_t*)&my_struct; ptr < (uint8_t*)&my_struct + sizeof(my_struct); ptr++)`, which is supported by normative 6.3.2/7: "When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object." This, assuming `uint8_t` counts as a character type. – Lundin Dec 11 '17 at 14:37
  • @Lundin: Indeed, `unsigned char` pointer arithmetic is fine. I've put that in. – Bathsheba Dec 11 '17 at 14:39
  • @AnttiHaapala Not again indeed. Which standard, which you aren't quoting, are you on about this time? Me I'm talking about the standard ISO 9899:2011 "Programming Languages - C", chapter 6.3.2.3/7. – Lundin Dec 11 '17 at 14:44