const char ascii_anim1[] = # include "ascii_anim1.h" ;

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The title statement  is from the Atmel PDCA_Example1.  In all the Atmel examples, the entire example is mostly a single file.  I, like most programmers , would prefer to have my program in multiple files. So I have been working to break PDCA_Example1 into multiple files.  In the PDCA_Example1, there are two ascii files - ascii_anim1.h and ascii_anim2.h   These files are referenced in the main file, outside of any function by:


const char ascii_anim1[] =
#   include "ascii_anim1.h"
;

const char ascii_anim2[] =
#   include "ascii_anim2.h"
;

Here is a snippet of one of the ascii files

" \r\n"
/*
 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
 */
"         / \r\n"
"        / \r\n"
"      <<O                                              O \r\n"
"        |                                          UC3/|> \r\n"
"       /|                                              | \r\n"
"      / |                                              | \r\n"
"AVR   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\x0C"
" \r\n"

 

In the program, as part of the PDCA interrupt, the following statements is made:


    if (animation_high_section) {
        pdca_reload_channel(PDCA_CHANNEL_USART_EXAMPLE,
                (void *)ascii_anim2, sizeof(ascii_anim2));
    }
    else {
        pdca_reload_channel(PDCA_CHANNEL_USART_EXAMPLE,
                (void *)ascii_anim1, sizeof(ascii_anim1));
    }

 

This is where I am having problems.  I have renamed ascii_anim1.h as ascii_anim1.c and added 

 

const char ascii_anim1[] = {

 

in front of the ascii file and }; at the end of the ascii file.  In addition I added

 

extern const char ascii_anim1[];

in an h file that is included in every c file.

 

When I compile the program the

  (void *)ascii_anim1, sizeof(ascii_anim1));

gives an error of 

"  invalid application of 'sizeof' to incomplete type 'const unsigned char[]'    "

 

So my question is how do I setup the ascii_anim1 file so the program will compile correctly?
 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What language are you using, C or C++?

 

---

 

Variant 1. If you absolutely want to keep using `sizeof` the way it is used in the original code.

 

In C, unfortunately, you have no elegant solution if you want to separate declaration and definition of your array. You will have to specify the array size explicitly and manually between the `[]` in the `extern` declaration. And you will have to maintain in manually to make sure it is always up-to-date. 

 

In C++ you have an elegant solution staring from C++17. You can declare your array in the header file as

 

extern inline const char ascii_anim1[] =
#   include "ascii_anim1.h"
;

I.e. basically use the original approach in the header file but include `inline` into the declaration.

 

---

 

Variant 2. If you don't mind abandoning `sizeof`.

 

Alternatively, you can simply abandon the original `sizeof` usage and export the actual array size from the definition site. For that you will have to declare the size as a separate variable

 

// Declaration site
extern const char ascii_anim1[];
extern const size_t ascii_anim1_size; 

and define and initialize it at the definition point

 

// Definition site
const char ascii_anim1[] =
#   include "ascii_anim1.h"
;
const size_t ascii_anim1_size = sizeof ascii_anim1;

Now, instead of `sizeof(ascii_anim2)` you will have to use `ascii_anim1_size`. This is not an equivalent replacement since now `ascii_anim1_size` is not a constant expression (not a compile-time constant), but it will work in the contexts you quoted.

Dessine-moi un mouton

Last Edited: Wed. Sep 2, 2020 - 04:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

  invalid application of 'sizeof' to incomplete type 'const unsigned char[]'

 

You can't do "sizeof" an extern char[] array.  (I'll assume that the #includes you're doing are NOT in the same file as the ISR.)

 

 

 

I would modify your ascii_anim.c file to have:

const char ascii_anim1[] =
#   include "ascii_anim1.h"
;
const char ascii_anim1_len = sizeof(ascii_anim1)

const char ascii_anim2[] =
#   include "ascii_anim2.h"
;

 

(actually, it bothers me a bit that the ascii_animN.h files are not "legal C" individually.  And it looks like your code is a good candidate for multi-dimension arrays (and PROGMEM) Real Soon Now.  (looks like "not an AVR", so perhaps you won't need the PROGMEM))

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
actually, it bothers me a bit that the ascii_animN.h files are not "legal C" individually. 
In a coding standard I used to use it would mandate that the data files were .i not .h in fact.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not a fan of defines, but...

 

 

//"ascii_anim2.h"

#define ASCII_ANIM2 \

    "1234" \

    "4567" \

    "\r\n"

 

 

 

//myfile.c

#include "ascii_anim2.h"

 

pdca_reload_channel(PDCA_CHANNEL_USART_EXAMPLE,
                (void *)ASCII_ANIM2, sizeof(ASCII_ANIM2)-1 ); //want 0?, probably not

 

//or use __builtin_strlen if its a string and you do not want the terminating 0

pdca_reload_channel(PDCA_CHANNEL_USART_EXAMPLE,
                (void *)ASCII_ANIM2, __builtin_strlen(ASCII_ANIM2) );

 

Last Edited: Wed. Sep 2, 2020 - 12:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think that xmacros will do what is desired.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For heavy text processing there are better language choices out there.

 

I'll get blasted for suggesting PERL but it is incredibly powerful. (but also quite terse and chock full of sigils that you can never remember)

 

I used it for processing multi megabyte report files to generate hundreds of smaller specialised files and found it quite capable.

 

Edit:

In my current project I'm using Python to generate C source files to create a translation database. The "machine generation" of C source concept may be useful to you.

 

Last Edited: Wed. Sep 2, 2020 - 09:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

N.Winterbottom wrote:
In my current project I'm using Python to generate C source files to create a translation database. The "machine generation" of C source concept may be useful to you.
I've done this a lot. I find Python makes generating C/C++ source very easy.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
N.Winterbottom wrote:
In my current project I'm using Python to generate C source files to create a translation database. The "machine generation" of C source concept may be useful to you.
I've done this a lot. I find Python makes generating C/C++ source very easy.
I've done that when I shouldn't have.

I have used Python to read header files to automatically copy enumeration constant values for use elsewhere, e.g. linker options.

GNU inline assembly reduces some of the need.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
GNU inline assembly reduces some of the need.
Given the choice of easy to use Python or tortuous inline GCC asm I know which I would choose !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My thanks for all the responses to my question.  At the age of 69, I think I will forgo learning a new language :-)   In the end I gave up on trying to have a single copy of 

const char ascii_anim1[] =
#	include "ascii_anim1.h"
;


const char ascii_anim2[] =
#	include "ascii_anim2.h"
;

but rather I ended up putting it in each file that used it.

 

This leads me to a follow up question on making calls to a function that is in a different file (posted as a new topic).

Kind regards,

David

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
skeeve wrote:
GNU inline assembly reduces some of the need.
Given the choice of easy to use Python or tortuous inline GCC asm I know which I would choose !

'Tain't that tortuous.

Like Python, 'tis something that has to be learned.

Just putting a constant into otherwise basic inline assembly 'tain't hard at all.

It also reduces the number of programs in the toolchain

and the number of distinct files in which a constant is used.

 

If for some reason I was averse to inline assembly and wanted the enum in the C file,

I'd use the enum in the C file, a #define with a different name in the assembly

and a static_assert in the C file to ensure that they were the same.

With some added complexity, I could use the same name.

 

Also generating C code with anything raises the issue of where to put the generated code.

'Tain't really source code.

Telling the IDE to compile something from an object directory might be difficult.

Also I like to be able to build from a read-only source tree.

That can be arranged from a hand-made make file,

but I'm not sure how many IDEs allow it.

 

My guess is that clawson runs the Python code by hand and treats its output as a source file.

If so, I'd hope he keeps the Python code and its input around as documentation.

 

BTW I like Python.

I have used it for code generation

I used it a lot more when, for whatever reason, I didn't trust the C preprocessor with ##.

I've used it to put an enum constant into an @file for the linker.

 

Iluvatar is the better part of Valar.