How can I return a 12 byte from a function?

Need some help…
I am getting a 12 byte data from SPI interface.

I got a function for read register, want to store 12 byte in “result”,
then return it when this function ends.
Is it possible?

Declare an array that can store the 12 elements. Pass the array to the function. Pack the data into the Array.

Use a global data area. Declare a global array of 12 bytes. Not what you asked, but it would do the job.

If you really want to return 12 bytes, you could pass 3 long ints by reference.

TanHadron:
If you really want to return 12 bytes, you could pass 3 long ints by reference.

.. or just pass an array of 12 bytes.

struct mydatas {
  char data[12];
};
mydatas f();

void setup() {
  mydatas foo = f();
}
void loop() {}

mydatas f() {
  mydatas myd;
  myd.data[4] = 4;
  return myd;
}

WisenedEE code probably meant the line to be:

  myd.data[4] = '4';

since it is a character array. If the purpose of the function is to change the 12 bytes in some way, yet not use global scope for the data, why not use:

void setup() {

  Serial.begin(9600);
 
}
void loop() {
  char data[12];
  f(data);
 
  Serial.println(data[4]);

}

void f(char c[]) {
 
  c[4] = '4';

}

econjack:
WisenedEE code probably meant the line to be:

  myd.data[4] = '4';

since it is a character array.

No, char is just the standard one byte type. So a char array of length n is universally known to be 12 bytes.

I misunderstood what you were trying to do.

I misunderstood what you were trying to do.

Weren't the comments clear enough? :slight_smile:

PaulS: good point! XD

This is a perfect example of what I call a silent cast. Anytime the data type for the expression on the right side of the assignment operator can fit the data type on the left side of the expression, there is no complaint from the compiler, as in the expression:

  myd.data[4] = 4;   // Silent cast

What the compiler is actually doing is:

  myd.data[4] = (char) 4;   // Documented cast

Although C and C++ do type checking, the compiler doesn't complain if it can figure things out on its own. Using the Bucket Analogy, the compiler barfs on

int i;
float x = 10.0;
i = x;   // Information could be lost

The assignment expression is a problem because you're trying to pour data from a 4 byte bucket into a 2 byte bucket, risking a loss of data. WisenedEE assignment works fine, but I didn't understand he wanted the compiler to do the cast. I think using an explicit cast is always better even if it's not needed as it better shows (i.e., documents) your intent. (I always dinged my students if they used a silent cast.)

This is a perfect example of what I call a silent cast.

C calls it an implicit cast. The compiler knows that a 4 byte value won't fit in a two byte memory location, so it generates a warning. The Arduino team has decided that it is not important to see that message.

The real problem, as I see it, it that WizenedEE's code is unnecessarily complicated. Reference variables were invented for just the purpose that OP wanted. Wrapping an array in a struct just so that a function can return a single address is useless overhead. Use a reference variable and pass the array address to the function.

PaulS: Exactly. That's why I suggested using a local array.

I was puzzled by WisenedEE statement:

No, char is just the standard one byte type. So a char array of length n is universally known to be 12 bytes.

because I didn't realize that an array length n is universally known to be 12. If you want to use a one byte type, why not define the array as a byte data type. Very confusing to me...

econjack:
PaulS: Exactly. That’s why I suggested using a local array.

I was puzzled by WisenedEE statement:

No, char is just the standard one byte type. So a char array of length n is universally known to be 12 bytes.

because I didn’t realize that an array length n is universally known to be 12. If you want to use a one byte type, why not define the array as a byte data type. Very confusing to me…

This brings up a question to the OP…

@milkbottlec
Are the individual bytes signed or unsigned values? Use data type byte if unsigned, char if signed. If mixed you may need a struct… And, if you are using any of the Stream based output methods, watch-out for the difference in how .print() handles byte vs char…

Maybe this is a suggestion:

// Do not remove the include below
#include "pointertest.h"


//The setup function is called once at startup of the sketch
char str[12];
char *ptr = &str[0];

void fptr(char *xptr){
	for (int i=0; i <12; i++){
		*xptr = char(i);
	}
}
void setup()
{
// Add your initialization code here
	char xstring[12];
	char *yptr = &xstring[0];
	fptr(yptr);

}

// The loop function is called in an endless loop
void loop()
{
//Add your repeated code here
	fptr(ptr);
}

In this example str is a 12byte buffer
*ptr = a pointer to the first byte in the buffer
fptr is a function that rexieves a pointer. Al it does is start filling the buffer with 12 values.

Here setup calls the function and so does loop. both give fptr a pointer and the function starts filling the 12 bytes of that address given to it.

econjack:
because I didn't realize that an array length n is universally known to be 12. If you want to use a one byte type, why not define the array as a byte data type. Very confusing to me...

Because byte is not standard C. char is the only standard C known-by-compiler one byte datatype. uint8_t is defined in stdint.h and byte is a nonportable arduinoism (although one I do like)

Arduino.h:

typedef uint8_t byte;

stdint.h:

typedef unsigned char uint8_t;

The real problem, as I see it, it that WizenedEE's code is unnecessarily complicated. Reference variables were invented for just the purpose that OP wanted. Wrapping an array in a struct just so that a function can return a single address is useless overhead. Use a reference variable and pass the array address to the function.

I understand and often use passing by reference but I don't really like it. It goes against the ideas of functional programming (passing by reference means there's side effects). It's also not great because defining a variable takes two lines: one to declare it and allocate space and another to call a function to fill it up with nice data. Of course, those are minor issues that people generally ignore. I was simply pointing out an alternative. Furthermore, the OP specifically asked for how to "return" 12 bytes. Of course, one could assume that the OP doesn't know what he/she needs which may be true, but it's hardly considered good form to berate someone for giving a solution to the literal question posted.

I misunderstood what you were trying to do.

I assumed it was assumed that people posting replies were trying to help the OP by posting solutions to their problems.

Maybe this is a suggestion:

pointertest.h: No such file or directory

This function is passed and returns an array of 12 int.,

int *funct (int *a) {
  for (int j=0; j <12; j++) {
    a[j] = j;
  }
  return a;
}

It’s redundant to both pass and return the same array, since the arg is passed by reference and, unless declared const can be altered in funct.

Of course, one could assume that the OP doesn't know what he/she needs which may be true, but it's hardly considered good form to berate someone for giving a solution to the literal question posted.

One need not berate a poster to point out alternatives that are conceptually simpler.

It's also not great because defining a variable takes two lines: one to declare it and allocate space and another to call a function to fill it up with nice data.

As opposed to how many lines of code to define the structure, allocate an instance, fill it with data, etc.?