sizeof pointer - getMotorsWithDriveSideType

ROBOTC v4.55

Background
I have a file called


setDrive.c

. It contains three functions,


setDrive(speed)

,


setDriveLeft(speed)

,


setDriveRight(speed)

. As you can probably imagine, these functions set the respective drive side to


speed

. The functions rely on a


#define DRIVE_MOTORS 4

, where four is the total number of drive motors (two on each side). In the file there are three different variations of the function, one for 2 drive motors, another for 4 drive motors, and yet another for 6. The functions also require specifically named drive motors, i.e. for four motors the drives must be named like


driveRightBack

or


driveLeftFront

. While this is totally usable, it feels clunky to me.

ROBOTC (with VEX2) stores what drive side (if any) a motor is, as a variable of type


TMotorDriveSide

. I would like to use this information in my functions.

My current code


struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
};
static _setDriveData setDriveData;

void setDriveInit() {
    getMotorsWithDriveSideType(driveLeft,  setDriveData.leftMotors );
    getMotorsWithDriveSideType(driveRight, setDriveData.rightMotors);

    setDriveData.leftMotorsNumb  = sizeof(setDriveData.leftMotors ) / sizeof(setDriveData.leftMotors [0]);
    setDriveData.rightMotorsNumb = sizeof(setDriveData.rightMotors) / sizeof(setDriveData.rightMotors[0]);
}

void setDriveLeft(int speed) {
    if (!setDriveData.initialized)
        setDriveInit();
    for (int i=0; i<setDriveData.leftMotorsNumb; i++){
        SetMotor(setDriveData.leftMotors*, speed);
    }
}

The problem
The lines which are not doing what they are supposed to are the


sizeof

ones.


sizeof(setDriveData.leftMotors)

returns


4

, no matter the length of


setDriveData.leftMotors

. This Stack Overflow answer makes me think that it is returning


4

because it is a pointer.


RobotCIntrinsics.c

, line 1844


getMotorsWithDriveSideType(TMotorDriveSide nType, TMotorList &nMotorList)

The


&nMotorList

means that it’s being passed as a pointer, right?

Thanks,
DMM

My code is attached (as a zip because Vex Forums doesn’t allow


.c

or


.txt

files).*
my code.zip (7.46 KB)

I’m not sure what RobotC is doing here. I never accept


Foo &bar

to a function, I always write it as


Foo *bar

because the former doesn’t work like you expect it to. Why do you need to use


TMotorList

anyway? I’ve gotten by fine just using


tMotor

.

I noticed you declare a


__setDriveData

as


static

. The


static

qualifier does not mean anything in RobotC because it uses a monolith file system, you aren’t hiding any data. Also, you could just simplify your struct declaration and initialization by doing this:


typedef struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} setDriveData;

I suggest you use arrays of


tMotor

instead, or write your own motor wrapper like I did: https://github.com/VTOW/BCI/blob/master/Modules/Control/motorControl.h#L78

sizeof(setDriveData.leftMotors) is returning 4 because that is the size of the array, sizeof works differently with arrays. There is however some inconsistency.

task main()
{
    tMotor  myarray[23];
    writeDebugStreamLine( "sizeof is %d", sizeof(myarray) );
}

This will give 23.

task main()
{
    short  myarray[23];
    writeDebugStreamLine( "sizeof is %d", sizeof(myarray) );
}

This, however, gives 46.

writeDebugStreamLine( "sizeof is %d", sizeof(myarray)/sizeof(myarray[0]) );

This will give the array length correctly for both cases.

for you code, I would rewrite as follows.

void setDriveInit() {
    getMotorsWithDriveSideType(driveLeft,  setDriveData.leftMotors );
    getMotorsWithDriveSideType(driveRight, setDriveData.rightMotors);

    setDriveData.leftMotorsNumb  = 0;
    setDriveData.rightMotorsNumb = 0;
    
    for(int i=0;i<sizeof(setDriveData.leftMotors );i++) {
      if( setDriveData.leftMotors* != -1 )
        setDriveData.leftMotorsNumb++;
    }
    for(int i=0;i<sizeof(setDriveData.rightMotors );i++) {
      if( setDriveData.rightMotors* != -1 )
        setDriveData.rightMotorsNumb++;
    }
        
    //setDriveData.leftMotorsNumb  = sizeof(setDriveData.leftMotors ) / sizeof(setDriveData.leftMotors [0]);
    //setDriveData.rightMotorsNumb = sizeof(setDriveData.rightMotors) / sizeof(setDriveData.rightMotors[0]);

**

Your code works amazingly, thanks JP. I believe that for teams only using the cortex,


i < sizeof(setDriveData.rightMotors)

can be simplified to


i < 4

, because the


sizeof

will always return


4

on cortex systems. NXT will always be


3

.

I have a kind of new question (which I don’t think merits its own post).
Why is line 1843,


RobotCIntrinsics.c

:


typedef tMotor TMotorList[4];

?
What happens in the case of a 10, or 12 motor pushbot? It is possible to set 5 motors to


driveRight

, but it appears the 5th just gets ignored. Why is the array 4, not 6?

I’m still learning, so I don’t really know what I should or shouldn’t be doing (or if there is a more efficient way of doing things). My code doesn’t use


TMotorList

. That was part of


RobotCIntrinsics.c

. There doesn’t appear to be any documentation on


getMotorsWithDriveSideType

, so I’m kind of winging it.

Thanks, I’ll do this. I was sort of copying and merging JPearman’s


SmartMotorLib.c

and


gyroLib2.c

. As I said before, I’ve been guessing my way through the coding, as I have little experience in C arrays and pointers/references. Could you explain why JPearman uses


static

in line 68, gyroLib2.c?

Care to give me an example?

Woah, waaayyy above my level :slight_smile: I’m 16, and the only C experience I have is in ROBOTC.

Update:
I removed the static, it compiled fine.
I tried to change


struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
};
_setDriveData setDriveData;

to


struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} setDriveData;

I now get a compile error of:


'&' Invalid parameter for reference variable. Call to 'getMotorsWithDriveSideType'. Parameter: 'TMotorList & nMotorList' is 'setDriveData.leftMotors' of type 'TMotorList'.

.
Any idea why?

He probably uses static for the same reason I do, to show intent. Even though static doesn’t end up meaning anything, it’s still shows what the programmer intends. I just wanted to point that out to you.

When I was talking about arrays of tMotor, I meant that if you want to specify a drive side, that’s a collection of motors, so why not use an array of tMotor instead of whatever RobotC is doing internally. It seems like james fixed you up, though.

Finally, about your change to your struct definition, what I linked is shorthand and you are missing a typedef. Perhaps this will make it clearer:
This code:


typedef struct foo_t {
  int x;
} foo;

is equivalent to this code:


struct foo_t {
  int x;
};
typedef struct foo_t foo;

I usually typedef my structs to make them easier to write. If you leave a struct as-is and don’t make it into a type, you need to carry the struct keyword.


struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
};

Both


_setDriveData setDriveData;

and


struct _setDriveData setDriveData;

compile cleanly.


typedef struct _setDriveData {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
};
_setDriveData setDriveData;

Adding


typedef

gives the following compiler warning:


'typedef' keyword has no impact since no 'name' is specified between '}' and ';'

I can change the code to:


typedef struct {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} _setDriveData;
_setDriveData setDriveData;

and it’s happy.

If I try


typedef struct _setDriveData{
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} setDriveData;

I get a compile error of:


'&' Invalid parameter for reference variable. Call to 'getMotorsWithDriveSideType'. Parameter: 'TMotorList & nMotorList' is 'setDriveData.leftMotors' of type 'TMotorList'.

Maybe I’m missing something simple. Here’s what I understand about the following code:


typedef struct foo_t {
  int x;
} foo;

This defines a type of struct called


foo_t

, which contains an integer


x

. I can make another struct with


int x

by typing


foo_t another_struct_with_int_x;

. Adding the


foo

at the end is the same as typing


foo_t foo;

.

Why do I get compile errors when all I do is combine the variable declaration with the struct?

Thanks for all your help :slight_smile:

I’m not sure what RobotC is doing internally in this case. You’ll have to turn to James for that one. It seems correct to me. Are you sure that error is being thrown from the struct and not from somewhere else?

This.

typedef struct {
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} _setDriveData;
_setDriveData setDriveData;

create a new type called _setDriveData and then creates a new variable called setDriveData.

This

typedef struct _setDriveData{
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} setDriveData;

create a new type called setDriveData, you need to then create a variable. If the variable needs to be called setDriveData then best to change the type definition.

typedef struct _setDriveData{
    bool initialized;
    TMotorList leftMotors, rightMotors;
    int leftMotorsNumb, rightMotorsNumb;
} TsetDriveData;

TsetDriveData setDriveData;

Thanks jp, I think I’ll stick to the original struct and variable declarations, just omitting the


static

.