How to manage static buffers

P

pozzugno

I'm programming on an embedded platform that lacks malloc()/free().
I can use only static allocation.

I'm writing two half-duplex protocols (protocol A and protocol B)
that will be implemented on several physical channels (at the moment,
two serial ports). Both protocols are of "slave" type: the program
waits for a request, processes it and answers. The payload (of request
and answer) should be packed in a different packet structure for protocol
A and B, but the payload are the same.

So I have one main function for each protocol:
int protocol_A(int fd, const void *buffer, size_t size);
int protocol_B(int fd, const void *buffer, size_t size);

And I have one function for each request:
int rqst_on(int fd, const void *payload, size_t size);
int rqst_off(int fd, const void *payload, size_t size);
...

fd is the file descriptor where the request was received and where
to write the answer (if any).
protocol_A() and protocol_B() parse the receiving buffer and call
the right request handler, passing the payload and its size.

Now the problem is how to handle the answer that should be packed
differently for each protocol (and I don't want to write two
request handlers, one for A and one for B).

I have two solutions, but both have some bad things.

The first is to allocate the answer buffer inside protocol_x():

int protocol_A(int fd, const void *buffer, size_t size) {
unsigned char answer[100];
size_t size = sizeof(answer);
...
n = rqst_on(fd, payload, size, answer, anssize);
/* Construct the packet and write it to fd */
}
int rqst_on(int fd, const void *payload, size_t size,
void *answer, size_t anssize) {
/* Parse the request and prepare the answer payload
* in answer buffer (maximum size is anssize) */
...
}

How big should be answer[]? Why protocol_x() function should care
about the length of the answer that appears a request problem?
At the moment 100 could be sufficient, but tomorrow? When I'll add
a new request, I'll write a new request handler function and I
would need a bigger answer buffer.

The second is to allocate the answer[] buffer inside request
handler function:

int protocol_A(int fd, const void *buffer, size_t size) {
...
rqst_on(fd, payload, size, answer_A);
}
void answer_A(int fd, const void *payload, size_t size) {
/* Create the answer for protocol A and write it to fd */
...
}
int rqst_on(int fd, const void *payload, size_t size) {
unsigned char answer[32];
...
answer_A(fd, answer, sizeof(answer));
}

Inside the request handler function I know for sure the exact
answer length and I won't risk to add a new request that needs
a bigger answer buffer.
....but the mechanism is more complex and I need a new answer_x()
function.

What do you prefer? Do you have other better alternatives?
 
T

tom st denis

I'm programming on an embedded platform that lacks malloc()/free().
I can use only static allocation.

Have you considered doing something like this

char heap[1024];

And then allocate your own blocks of memory out of that with malloc/
free that you write?

On most bare metal platforms the usual way is either through a .bss
segment allocation (global array) or to just assume you have a region
of memory available for your task (obviously not portable code at that
point).

Tom
 
J

James Kuyper

I'm programming on an embedded platform that lacks malloc()/free().
I can use only static allocation.

Actually, every variable in your code below has automatic storage
duration, not static storage duration. Variables with automatic storage
duration have a lifetime that ends when execution of the associated
block ends. The lifetime of statically allocated variables would not end
until execution of the entire program had ended.
I'm writing two half-duplex protocols (protocol A and protocol B)
that will be implemented on several physical channels (at the moment,
two serial ports). Both protocols are of "slave" type: the program
waits for a request, processes it and answers. The payload (of request
and answer) should be packed in a different packet structure for protocol
A and B, but the payload are the same.

So I have one main function for each protocol:
int protocol_A(int fd, const void *buffer, size_t size);
int protocol_B(int fd, const void *buffer, size_t size);

And I have one function for each request:
int rqst_on(int fd, const void *payload, size_t size);
int rqst_off(int fd, const void *payload, size_t size);
...

fd is the file descriptor where the request was received and where
to write the answer (if any).
protocol_A() and protocol_B() parse the receiving buffer and call
the right request handler, passing the payload and its size.

Now the problem is how to handle the answer that should be packed
differently for each protocol (and I don't want to write two
request handlers, one for A and one for B).

I have two solutions, but both have some bad things.

The first is to allocate the answer buffer inside protocol_x():

Why does this function have a 'size' parameter? It makes no use of it.
int protocol_A(int fd, const void *buffer, size_t size) {
unsigned char answer[100];
size_t size = sizeof(answer);

Please note that this definition of 'size' hides the parameter of the
same name.
...
n = rqst_on(fd, payload, size, answer, anssize);

What is anssize?
/* Construct the packet and write it to fd */
}
int rqst_on(int fd, const void *payload, size_t size,
void *answer, size_t anssize) {
/* Parse the request and prepare the answer payload
* in answer buffer (maximum size is anssize) */

What does this code do with 'size' and 'anssize'?
...
}

How big should be answer[]?

There's no way of knowing from the information you've given us. The
questions I've asked above would help resolve that issue.

However, once you do know how big answer[] should be, it's possible that
a new feature of C99 called variable length arrays would be helpful. You
would first calculate, by whatever means, the value of anssize. Then you
can define

unsigned char answer[anssize);
Why protocol_x() function should care
about the length of the answer that appears a request problem?

I'm not quite sure what you're asking here, but my best guesses all lead
to the same response: I don't know, because you've not given us enough
information to answer that question.
At the moment 100 could be sufficient, but tomorrow? When I'll add
a new request, I'll write a new request handler function and I
would need a bigger answer buffer.

The second is to allocate the answer[] buffer inside request
handler function:

int protocol_A(int fd, const void *buffer, size_t size) {
...
rqst_on(fd, payload, size, answer_A);
}
void answer_A(int fd, const void *payload, size_t size) {
/* Create the answer for protocol A and write it to fd */
...
}
int rqst_on(int fd, const void *payload, size_t size) {
unsigned char answer[32];
...
answer_A(fd, answer, sizeof(answer));
}

Inside the request handler function I know for sure the exact
answer length and I won't risk to add a new request that needs
a bigger answer buffer.

That looks like a better solution to me. If answer[] were in fact
statically allocated, that would be a reasonable reason for avoiding the
creation of multiple request functions, since each one you added would
waste additional space. However, since answer[] has automatic storage
duration, I don't see any good reason to avoid making multiple request
functions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top