How can a library identify the project it's in?

Hi,

I have a data-logger class that I use in a number of projects. The logger uses a buffer (an array of characters) to hold data before doing an periodic write to file.

The buffer (and it's size) is defined in the logger class, and is set at design-time, not run time (I understand that arrays have to be fixed size).

I use the data logger in several different projects, and each project has a different amount of free ram that can be allocated to the data logger. Currently each time I compile and upload a project using this library I have to remember to manually edit the .h file for the data logger to allocate the correct amount of memory to the buffer.

What I'd really like to be able to do is something like this....

#ifdef project == P1
  bufferSize=200;
#elif project == P2
  bufferSize=500;
#else
  bufferSize=1000;
#endif

Where P1/P2 is the name of the project - and therefore I don't need to remember to tweak the library each time I switch between projects.

Based on some past posts, I've experimented with FILE but this returns the name of the current library, not the name of the top-level sketch or project name.

Any suggestions please?

At compile time, the library has no idea that it will ever even be used. It certainly has no idea (nor does the compiler) what code might eventually use it.

The amount of memory to use should be something that the sketch is responsible for telling the library, through the constructor.

At compile time, the library has no idea that it will ever even be used

I though that a check is made as to what objects and functions are actually used? and if they’re not used the they won’t be included in the build? If I #include a library, but then don’t use any objects from that library then resulting excutable will be no bigger than if I didn’t #include it? - doesn’t this mean that something has checked if the library is being used?

The amount of memory to use should be something that the sketch is responsible for telling the library, through the constructor.

I though that an array size has to be hard-coded? Can I pass a value (say 512) via the constructor and then use that to create an array of 512 bytes?

I though that a check is made as to what objects and functions are actually used?

That is done by the linker, after all the separate compilation units have been compiled.

If I #include a library, but then don't use any objects from that library then resulting excutable will be no bigger than if I didn't #include it?

Correct, unless the library creates instances automatically, like HardwareSerial does.

doesn't this mean that something has checked if the library is being used?

Yes, the linker does. The compiler doesn't care whether you have defined a file to be compiled for no good reason.

I though that an array size has to be hard-coded?

No. malloc() and new can be used (with a great deal of caution) to create dynamic arrays.

Thanks PaulS - that's cleared up some questions

malloc() and new can be used (with a great deal of caution) to create dynamic arrays.

So, if I shouldn't really be using 'malloc' or 'new', is there any way to change the size of an array in a library depending on which project it's in?

I have a data logger class which I use in three different projects, in the simplest I can afford a buffer (i.e. a character array) of size 512, in the most complex project (i.e. the one that uses the most memory) I can only afford to allocate 150 bytes to the buffer. The other one normally gets about 300 bytes.

At the moment I make a hard-coded change to the library each time I upload, but normally only after I've forgotten about it for a couple of times!

Fulliautomatix:
The buffer (and it’s size) is defined in the logger class, and is set at design-time, not run time (I understand that arrays have to be fixed size).

Maybe you could turn this on its head.

Define the buffer in the program and pass a reference to the buffer to the library.

…R

Fulliautomatix:
Thanks PaulS - that's cleared up some questions

So, if I shouldn't really be using 'malloc' or 'new', is there any way to change the size of an array in a library depending on which project it's in?

There's nothing wrong with using malloc() in the situation you have described. It's free()'s followed by malloc()'s that can get you in trouble, or allocating blindly. A one time allocation for the life of the application should be fine as long as you respect your known memory limits when you allocate. Make sure the calling program specifies the size, don't let the logger do that. When you compile, you can assess your memory usage and decide whether the maximum allotment (which you know, because you coded it) will fit.

So allocate once, and only once, expecting to use your allocation to last for the life of the program. Or else use the approach in reply #5. The difference with #5, is that the exact memory use will be reported to you at compile time so you don't have to calculate it.

We do have dynamic allocation every time we have a function that gets passed args or has local variables. They live on the stack and get lost with scope. It's not a bad idea to be aware that nested calls can lead to crashes.

GoForSmoke:
We do have dynamic allocation every time we have a function that gets passed args or has local variables. They live on the stack and get lost with scope. It's not a bad idea to be aware that nested calls can lead to crashes.

It's somewhat safer because it is is FILO. Thus one ended management. If you use malloc() and free() in a FILO fashion, I believe (but someone more knowledgeable about the internal workings of it might correct me) you should be okay. It's when you allocate in a non-FILO way that you get into trouble, because it can lead to fragmentation. If you malloc A and B and then free A, you leave a gap that malloc can only fill with an equal or smaller sized block. That is the beginning of fragmentation. If you free() only the last thing that you malloc()'d, you shouldn't create any gaps and you will not have fragmentation. At least, that is my understanding of it.

At least, that is my understanding of it.

That understanding is correct.

OP: I did say "malloc() and new can be used (with a great deal of caution) to create dynamic arrays.".

That caution means that if your constructor allocates memory, your destructor must deallocate the memory, or you have a memory leak.

That caution means that you need to check that the allocation succeeded, rather than assuming that it did.

That caution means that you need to be reasonable in allocating memory. Allocating space for an array of 3000 longs, on a 328-based Arduino is not being reasonable.

Writing functions that nest deeply and use a lot of stack can be one way to crash the program though not as 'efficiently' as recursion. :slight_smile:

It's something to look out for even as the potential is used.

PS - it's just more reasons to write less indented code.