1

I'm compiling C++ source (main.cpp) with a C header (hps_linux.h). The code in hps_linux.h is:

#ifndef HPS_LINUX_H_
#define HPS_LINUX_H_

#include <stdbool.h>
#include <stdint.h>

#include "socal/hps.h"

int fd_dev_mem = 0;
void   *h2f_lw_axi_master     = NULL;
size_t h2f_lw_axi_master_span = ALT_LWFPGASLVS_UB_ADDR -ALT_LWFPGASLVS_LB_ADDR + 1;
size_t h2f_lw_axi_master_ofst = ALT_LWFPGASLVS_OFST;

#endif

hps_linux.h includes hps.h, that has the next defines:

#define ALT_LWFPGASLVS_OFST        0xff200000
#define ALT_LWFPGASLVS_ADDR        ALT_CAST(void *, (ALT_CAST(char *, ALT_HPS_ADDR) + ALT_LWFPGASLVS_OFST))
#define ALT_LWFPGASLVS_LB_ADDR     ALT_LWFPGASLVS_ADDR
#define ALT_LWFPGASLVS_UB_ADDR     ALT_CAST(void *, ((ALT_CAST(char *, ALT_LWFPGASLVS_ADDR) + 0x200000) - 1))

My main.cpp includes hps_linux.h . I'm compiling like this:

gcc -Wall -std=gnu99 hps_linux.c -o hps_linux.o
g++ -Wall -std=c++0x main.cpp -o main 

And it throws the next error:

hps_linux.h: error: invalid use of 'void'

In line:

size_t h2f_lw_axi_master_span = ALT_LWFPGASLVS_UB_ADDR -ALT_LWFPGASLVS_LB_ADDR + 1;

When I compile it with a main written in C (main.c), it works.

  • 1
    As an aside, you might need to wrap the header inclusion with `extern("C"){ #include "hps_linux.h" }` in C++. – paddy May 11 '17 at 00:56
  • 4
    We would need to see the definition of `ALT_CAST`. The line with the error is suspicious: if `ALT_CAST` provides a `void*` type, then you're attempting to do pointer arithmetic on a `void*` which is [not allowed](http://stackoverflow.com/q/4019671/1553090). – paddy May 11 '17 at 00:59
  • What @paddy said. Looks to me like those macros are likely doing pointer arithmetic on void pointers. – Carey Gregory May 11 '17 at 01:04
  • Did you compile with `-Wall` and `-Wextra`? – Erik W May 11 '17 at 01:12
  • The code in the header defines (including initializing) variables; it shouldn't. If more than one file includes the header, more than one file defines the variables, and the corresponding object files can't be linked into a single program without going through unnecessary shenanigans. Headers declare variables; source files define them. – Jonathan Leffler May 11 '17 at 05:51

1 Answers1

3

Looking at the source code here, we have:

#ifdef __ASSEMBLY__
#    define ALT_CAST(type, ptr)  ptr // <-- not (ptr)???
#else
#    define ALT_CAST(type, ptr)  ((type) (ptr))
#endif  /* __ASSEMBLY__ */

Now, we have:

size_t h2f_lw_axi_master_span = ALT_LWFPGASLVS_UB_ADDR - ALT_LWFPGASLVS_LB_ADDR + 1;

Partially expanding the macros, we have:

size_t h2f_lw_axi_master_span = ALT_CAST(void *, ALT_CAST(char *, ...)) - ALT_CAST(void *, ALT_CAST(char *, ...)) + 1;

Now, if __ASSEMBLY__ is set, this line is:

size_t h2f_lw_axi_master_span = ... - ... + 1;

Both ... expressions are integer, so this is OK. However, if __ASSEMBLY__ is not set, this line is:

size_t h2f_lw_axi_master_span = (void *) (...) - (void *) (...) + 1;

Subtracting two void pointers is not defined, so the compiler gives up.

Therefore, you need to ensure __ASSEMBLY__ is defined; one way would be:

g++ -Wall -D__ASSEMBLY__ -std=c++0x main.cpp -o main

However, this might cause problems as you should be relying on the earlier header files to set it correctly.

Update: A quick search of the git archive does not show __ASSEMBLY__ being set, and given the name it suggests it should be a compiler built-in...

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114