Getting embedded PACKED_STRUCT definition to compile under g++ - c

I'm working on a smart meter project, ARM, keil compiler. I want to compile some of the more complex logic under g++ to run regression tests. I'm having a problem with some include files defining the interface to WMBus stack we purchased.
PACKED_STRUCT( typedef struct S_WMBUS_ADDR_T
{
/*! Manufacturer ID */
uint8_t pc_manufr[WMBUS_ADDR_MANUFR_LEN];
/*! Ident number */
uint8_t pc_ident[WMBUS_ADDR_IDENT_LEN];
/*! Version */
uint8_t c_version;
/*! Type */
uint8_t c_type;
}, s_wmbus_addr_t);
PACKED_STRUCT is defined in a compiler sensitive include file:
#elif defined (__GNUC__)
#define PACKED_STRUCT(__declaration__, __name__) \
__declaration__ __attribute__ ((__packed__)) __name__
...
#elif defined(__arm__)
#ifdef __ARMCC_VERSION
#define PACKED_STRUCT(__declaration__, __name__) \
__packed __declaration__ __name__
And I always get the following error messages:
error: types may not be defined in parameter types
error: typedef declaration invalid in parameter declaration
I can so no way around this other than by editing the include file to remove the PACKED_STRUCT. Obviously I won't edit the files directly, I'll copy them, edit them, and use the -I directive to make it find my modified files under G++
The error message seems to be saying you cannot declare a type as an argument to a macro?
Note even if I redeclare:
#define PACKED_STRUCT(__declaration__, __name__) \
__declaration__ __name__
I am using the -std=c++11 flag to g++ but removing this flag solves nothing, but makes a system include fail
Is there any way I can define PACKED_STRUCT to make the unmodified code compile under g++?

#LP You are right, though I'm not sure why right now. This code compiles:
I must have a wrong include file slipping through somehow.
typedef unsigned char uint8_t;
#define WMBUS_ADDR_MANUFR_LEN 4
#define WMBUS_ADDR_IDENT_LEN 4
#define PACKED_STRUCT(__declaration__, __name__) \
__declaration__ __attribute__ ((__packed__)) __name__
PACKED_STRUCT( typedef struct S_WMBUS_ADDR_T
{
/*! Manufacturer ID */
uint8_t pc_manufr[WMBUS_ADDR_MANUFR_LEN];
/*! Ident number */
uint8_t pc_ident[WMBUS_ADDR_IDENT_LEN];
/*! Version */
uint8_t c_version;
/*! Type */
uint8_t c_type;
}, s_wmbus_addr_t);
s_wmbus_addr_t hello;

Related

Forward declaration issue, two compilers

I've been developing in C using eclipse as my IDE in my virtual machine with ubuntu, I've made some progress and I wanted to test them in the real product which is an embedded system using powerpc.
In order to compile that program for our product I use Code::Blocks in Windows but the compiler is a powerpc version of the gcc.
The same code is giving me an error in the powerpc version that doesn't appear in the ubuntu version.
I have two header files gral.h and module_hand.h as follows:
The gral.h file:
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
#include "module_hand.h"
typedef struct PROFILE
{
module_t mod; // this one comes from module_hand.h
int var1; // some other random variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */
The module_hand.h is defined as follows
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <stdint.h>
#include "gral.h"
typedef struct PROFILE profile_t;
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
int Mod_Init(profile_t *profile);
/* some other random functions */
#endif /* HEADERS_MODULE_HAND_H_*/
As you'll see, I don't use the PROFILE struct in the module struct, But I declare it forward to use it in the declaration of the Mod_Init function
This gives me a Error: redefinition of typedef 'profile_t'
and error: previous declaration of 'profile_t' was here
If I remove the forward declaration the error is Error: parse error before '*' token
where the line number is the line of the function declaration.
My doubt is what am I missing, and why gcc in Ubuntu does compile it with no problem.
Your powerpc compiler is enforcing the C99 rule that
If an identifier has no linkage, there shall be no more than one
declaration of the identifier (in a declarator or type specifier) with
the same scope and in the same name space, except for tags as
specified in 6.7.2.3.
(C99 6.7/3)
Your Linux compiler is observing the relaxed version of that rule that was introduced in C11:
If an identifier has no linkage, there shall be no more than one
declaration of the identifier (in a declarator or type specifier) with
the same scope and in the same name space, except that:
a typedef name may be redefined to denote the same type as it currently does, provided that type is not a variably modified type;
tags may be redeclared as specified in 6.7.2.3.
(C11 6.7/3; also C17 6.7/3)
Supposing that the compilation options are the same, the behavior difference surely arises from using different versions of GCC. More recent versions default to more recent versions of the language.
You could try adding -std=gnu11 or -std=c11 to the command-line options (for both targets) to try to get consistency. If your powerpc version of GCC is too old to accept those then you really need to update to a newer version.
Note also, however, that you don't need to have this problem in the first place. Given that module_hand.h includes gral.h, the former has no need whatever to redefine a typedef that the latter already defines.
Moreover, the fact that these two headers each include the other is a strong suggestion that they ought to be combined into one. Multiple-inclusion guards prevent an actual loop, but they are not an adequate solution.
In the gral.h header file, you define profile_t using typedef, then you redefine profile_t with another typedef in module_hand.h. You should just define the struct PROFILE in gral_h and include gral.h in module_hand.h.
gral.h:
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
#include "module_hand.h"
typedef struct PROFILE {
module_t mod; // this one comes from module_hand.h
int var1; // some other random variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */:
module_hand.h:
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <stdint.h>
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
int Mod_Init(struct PROFILE *profile);
/* some other random functions */
#endif /* HEADERS_MODULE_HAND_H_*/
Well I read your answers and comments and decided to try another approach.
As some of you said, I had some kind of recursion, I wanted to keep every structure within its respective header file, but now, I dropped the idea and merged the structures in one file only.
My new approach:
Gral.h
#ifndef HEADERS_GRAL_H_
#define HEADERS_GRAL_H_
typedef struct module
{
char name[30]; // name of module
char rev[30]; // module revision
char mfr[30]; // manufacturer
} module_t;
typedef struct PROFILE {
module_t mod; // this one comes from module_hand.h
int var1; // some other variables
} profile_t;
#endif /* HEADERS_GRAL_H_ */:
Module.h
#ifndef HEADERS_MODULE_HAND_H_
#define HEADERS_MODULE_HAND_H_
#include <Gral.h>
int Mod_Init(profile_t *profile);
/* some other functions */
#endif /* HEADERS_MODULE_HAND_H_*/
And when any other structure comes up, I'll declare it in Gral.h and include the header file.
Regarding the compilers, they aren't the same version. The powerpc is quite old now. That would explain the powerpc compilation errors.
Thank you again.

Compilation headers for 64-bit ARM64 Raspberry Pi for Yate?

When I try to compile Nuand's Yate software on 64-bit (ARM64) Ubuntu 21.04 on a Raspberry Pi 4, I get architecture support headers errors:
~/software/bts/yate$ make
make -C ./engine all
make[1]: Entering directory '/home/parallels/software/bts/yate/engine'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/home/parallels/software/bts/yate/engine'
make -C ./modules all
make[1]: Entering directory '/home/parallels/software/bts/yate/modules'
make -C ../libs/miniwebrtc
make[2]: Entering directory '/home/parallels/software/bts/yate/libs/miniwebrtc'
g++ -Wall -I. -I./audio/common/processing -I./audio/common/vad -I./audio/processing/aec -I./audio/processing/aecm -I./audio/processing/agc -I./audio/processing/ns -I./audio/processing/utility -I./system_wrappers -O2 -Wno-overloaded-virtual -fno-exceptions -fPIC -DHAVE_GCC_FORMAT_CHECK -DHAVE_BLOCK_RETURN -DWEBRTC_NS_FLOAT=true -c -o audio/common/resampler/resampler.o audio/common/resampler/resampler.cc
In file included from ./audio/common/processing/signal_processing_library.h:22,
from audio/common/resampler/resampler.cc:19:
./typedefs.h:104:2: error: #error Please add support for your architecture in typedefs.h
104 | #error Please add support for your architecture in typedefs.h
| ^~~~~
make[2]: *** [Makefile:263: audio/common/resampler/resampler.o] Error 1
make[2]: Leaving directory '/home/parallels/software/bts/yate/libs/miniwebrtc'
make[1]: *** [Makefile:448: ../libs/miniwebrtc/libminiwebrtc.a] Error 2
make[1]: Leaving directory '/home/parallels/software/bts/yate/modules'
make: *** [Makefile:186: modules] Error 2
When I check the typedefs.h header, I see arm64 support is not added yet:
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This file contains platform-specific typedefs and defines.
#ifndef WEBRTC_TYPEDEFS_H_
#define WEBRTC_TYPEDEFS_H_
// Reserved words definitions
// TODO(andrew): Look at removing these.
#define WEBRTC_EXTERN extern
#define G_CONST const
#define WEBRTC_INLINE extern __inline
// Define WebRTC preprocessor identifiers based on the current build platform.
// TODO(andrew): Clean these up. We can probably remove everything in this
// block.
// - TARGET_MAC_INTEL and TARGET_MAC aren't used anywhere.
// - In the few places where TARGET_PC is used, it should be replaced by
// something more specific.
// - Do we really support PowerPC? Probably not. Remove WEBRTC_MAC_INTEL
// from build/common.gypi as well.
#if defined(WIN32)
// Windows & Windows Mobile.
#if !defined(WEBRTC_TARGET_PC)
#define WEBRTC_TARGET_PC
#endif
#elif defined(__APPLE__)
// Mac OS X.
#if defined(__LITTLE_ENDIAN__ )
#if !defined(WEBRTC_TARGET_MAC_INTEL)
#define WEBRTC_TARGET_MAC_INTEL
#endif
#else
#if !defined(WEBRTC_TARGET_MAC)
#define WEBRTC_TARGET_MAC
#endif
#endif
#else
// Linux etc.
#if !defined(WEBRTC_TARGET_PC)
#define WEBRTC_TARGET_PC
#endif
#endif
// Derived from Chromium's build/build_config.h
// Processor architecture detection. For more info on what's defined, see:
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
// http://www.agner.org/optimize/calling_conventions.pdf
// or with gcc, run: "echo | gcc -E -dM -"
// TODO(andrew): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN?
#if defined(_M_X64) || defined(__x86_64__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86_64
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(_M_IX86) || defined(__i386__)
#define WEBRTC_ARCH_X86_FAMILY
#define WEBRTC_ARCH_X86
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__ARMEL__)
// TODO(andrew): We'd prefer to control platform defines here, but this is
// currently provided by the Android makefiles. Commented to avoid duplicate
// definition warnings.
//#define WEBRTC_ARCH_ARM
// TODO(andrew): Chromium uses the following two defines. Should we switch?
//#define WEBRTC_ARCH_ARM_FAMILY
//#define WEBRTC_ARCH_ARMEL
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
#elif defined(__mips__)
#define WEBRTC_ARCH_32_BITS
#define WEBRTC_BIG_ENDIAN
#elif defined(__powerpc64__)
#define WEBRTC_ARCH_PPC64 1
#define WEBRTC_ARCH_64_BITS
#ifdef __LITTLE_ENDIAN__
#define WEBRTC_ARCH_LITTLE_ENDIAN
#define WEBRTC_LITTLE_ENDIAN
#else
#define WEBRTC_ARCH_BIG_ENDIAN
#define WEBRTC_BIG_ENDIAN
#endif
#elif defined(__powerpc__)
#define WEBRTC_ARCH_PPC 1
#define WEBRTC_ARCH_32_BITS
#ifdef __LITTLE_ENDIAN__
#define WEBRTC_ARCH_LITTLE_ENDIAN
#define WEBRTC_LITTLE_ENDIAN
#else
#define WEBRTC_ARCH_BIG_ENDIAN
#define WEBRTC_BIG_ENDIAN
#endif
#else
#error Please add support for your architecture in typedefs.h
#endif
#if defined(__SSE2__) || defined(_MSC_VER)
#define WEBRTC_USE_SSE2
#endif
#if defined(WEBRTC_TARGET_PC)
#if !defined(_MSC_VER)
#include <stdint.h>
#else
// Define C99 equivalent types.
// Since MSVC doesn't include these headers, we have to write our own
// version to provide a compatibility layer between MSVC and the WebRTC
// headers.
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#endif
#if defined(WIN32)
typedef __int64 WebRtc_Word64;
typedef unsigned __int64 WebRtc_UWord64;
#else
typedef int64_t WebRtc_Word64;
typedef uint64_t WebRtc_UWord64;
#endif
typedef int32_t WebRtc_Word32;
typedef uint32_t WebRtc_UWord32;
typedef int16_t WebRtc_Word16;
typedef uint16_t WebRtc_UWord16;
typedef char WebRtc_Word8;
typedef uint8_t WebRtc_UWord8;
// Define endian for the platform
#define WEBRTC_LITTLE_ENDIAN
#elif defined(WEBRTC_TARGET_MAC_INTEL)
#include <stdint.h>
typedef int64_t WebRtc_Word64;
typedef uint64_t WebRtc_UWord64;
typedef int32_t WebRtc_Word32;
typedef uint32_t WebRtc_UWord32;
typedef int16_t WebRtc_Word16;
typedef char WebRtc_Word8;
typedef uint16_t WebRtc_UWord16;
typedef uint8_t WebRtc_UWord8;
// Define endian for the platform
#define WEBRTC_LITTLE_ENDIAN
#else
#error "No platform defined for WebRTC type definitions (typedefs.h)"
#endif
#endif // WEBRTC_TYPEDEFS_H_
So I reported this error to manufacturer Nuand, but they were not responding quickly on how to resolve these issues. So if I would add support for the raspberry pi manually, What's the correct way to add support for ARM64 without resulting into errors after compilation?
I tried:
#elif defined(__aarch64__)
#define WEBRTC_ARCH_64_BITS
#define WEBRTC_ARCH_LITTLE_ENDIAN
But it didn't result into a working Yate binary:
make[1]: Leaving directory '/home/yate/yate-rc-2/yate/conf.d'
make: *** [Makefile:259: install-api] Error 1

Compile time assertion as part of an expression but without _Static_assert

Ultimately, I want a compile-time-const macro that in itself includes an assertion.
With a real _Static_assert, I can do something like
#define CEXPR_MACRO_WITH_ASSERTION(Assertion) sizeof(struct{char c; _Static_assert(Assertion,""); })?0:42
(meant for stuff like "compile-time-assert" that the macro value computation won't overflow on any target, and I'd like to keep the assertion in the macro so that it's tightly coupled with the value) but compilers like tcc don't have static asserts so I'd need to emulate it.
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT[(Cexpr)?1:-1]
is a common way to do it but with that extern I can't use it in a struct so I could split it in two
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])] /*ignore Msg for simplicity's sake*/
and use the underscore version in the CEXPR_MACRO_WITH_ASSERTION, but in function context, this will give false positives on compilers that support structs with VLAs in them:
#define STATIC_ASSERT(Cexpr,Msg) extern STATIC_ASSERT_(Cexpr,Msg)
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr))?1:-1])]
#define CEXPR_MACRO_WITH_ASSERTION(Assert) (sizeof(struct{char c; STATIC_ASSERT_(Assert,""); })?0:42)
int main(void)
{
int x = 0;
CEXPR_MACRO_WITH_ASSERTION(x);
} //compiles on tcc and gcc (clang rejects it because of the vla in a struct)
so I effectively need:
#define STATIC_ASSERT_(Cexpr,Msg) char STATIC_ASSERT[sizeof(char [((Cexpr)&&ENFORCE_ICEXPR(Cexpr))?1:-1])]
Now I realize on tcc in particular, ENFORCE_ICEXPR (enforce integer constant expression) could be simply replaced with __builtin_constant_p but I was curious if I could do it without the platform dependency.
So I thought I could test Cexpr by trying to assign it to an enum constant and I came up with:
#define ENFORCE_Z(X) _Generic(0LL+(X),ullong:(X),llong:(X)) /*could be just `+(X)` cuz I don't care about floats*/
#define ENFORCE_ICEXPR(X) sizeof( void (*)(enum { ENFORCE_ICEXPR = (int)ENFORCE_Z(X) } ) )
but this gets gcc and clang complaining (unsilencably in gcc's case) about the enum not being visible outside of the declaration (which, incidentally, was the intention here) so I resorted to
#define ENFORCE_ICEXPR(X) sizeof(enum { BX_cat(ENFORCE_ICEXPR__,__COUNTER__) = (int)ENFORCE_Z(X) })
relying on the nonstandard magic macro, __COUNTER__.
My question is, is there a better way to write ENFORCE_ICEXPR(X)?
Perl uses a bit-field instead of an array to define a static_assert fallback:
#define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
#define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
#define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)
No compiler implements variable length bit-fields.

Purpose of #define-ing symbol as itself in C [duplicate]

I came across some C code where the author uses the following idiom all over the place:
typedef __int32 FOO_INT32;
#define FOO_INT32 FOO_INT32
What is the point of doing this? Shouldn't the typedef be enough? It is a workaround for some wonky C compilers out there?
With the #define instruction, you'll then be able to test if the typedef has been done somewhere else in the code using :
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
It's a practice that's sometimes done in headers. The #define allows for compile-time testing of the existence of the typedef. This allows code like:
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
or as a true guard #define, similar to header file guards.
#ifndef FOO_INT32
typedef int FOO_INT32
#define FOO_INT32 FOO_INT32
#endif
It's not necessarily a good practice, but it has its uses, especially when you have some headers which use types defined by other libraries, but you want to provide your own substitutes for cases when you're not using those libraries at all.
Another reason is that a standard might require definitions to be macros.
Snippet from glibc netinet/in.h:
/* Standard well-defined IP protocols. */
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
#define IPPROTO_IP IPPROTO_IP
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
#define IPPROTO_ICMP IPPROTO_ICMP
IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
#define IPPROTO_IGMP IPPROTO_IGMP
Here enum symbols are also exported as macros as required by the relevant POSIX spec, quoting:
The header shall define the following macros for use as
values of the level argument of getsockopt() and setsockopt():
IPPROTO_IP
Internet protocol.
IPPROTO_IPV6
Internet Protocol Version 6.
...
This pattern is also useful for feature-detection of registers in microprocessors, as in this question. For instance, there may be two similar header files, one of which defines one timer, and one that defines 2:
cheapprocessor.h:
#define TMR1 TMR1
extern volatile int TMR1;
expensiveprocessor.h:
#define TMR1 TMR1
extern volatile int TMR1;
#define TMR2 TMR2
extern volatile int TMR2;
Which means in your main code, when you include a generic processor.h that delegates to the appropriate header for the target, you can detect features:
#include <processor.h>
#ifdef TMR2
x = TMR2;
#else
x = 0; // no timer, probably because we're on the cheaper model
#endif

What is the point of saying "#define FOO FOO" in C?

I came across some C code where the author uses the following idiom all over the place:
typedef __int32 FOO_INT32;
#define FOO_INT32 FOO_INT32
What is the point of doing this? Shouldn't the typedef be enough? It is a workaround for some wonky C compilers out there?
With the #define instruction, you'll then be able to test if the typedef has been done somewhere else in the code using :
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
It's a practice that's sometimes done in headers. The #define allows for compile-time testing of the existence of the typedef. This allows code like:
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
or as a true guard #define, similar to header file guards.
#ifndef FOO_INT32
typedef int FOO_INT32
#define FOO_INT32 FOO_INT32
#endif
It's not necessarily a good practice, but it has its uses, especially when you have some headers which use types defined by other libraries, but you want to provide your own substitutes for cases when you're not using those libraries at all.
Another reason is that a standard might require definitions to be macros.
Snippet from glibc netinet/in.h:
/* Standard well-defined IP protocols. */
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
#define IPPROTO_IP IPPROTO_IP
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
#define IPPROTO_ICMP IPPROTO_ICMP
IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
#define IPPROTO_IGMP IPPROTO_IGMP
Here enum symbols are also exported as macros as required by the relevant POSIX spec, quoting:
The header shall define the following macros for use as
values of the level argument of getsockopt() and setsockopt():
IPPROTO_IP
Internet protocol.
IPPROTO_IPV6
Internet Protocol Version 6.
...
This pattern is also useful for feature-detection of registers in microprocessors, as in this question. For instance, there may be two similar header files, one of which defines one timer, and one that defines 2:
cheapprocessor.h:
#define TMR1 TMR1
extern volatile int TMR1;
expensiveprocessor.h:
#define TMR1 TMR1
extern volatile int TMR1;
#define TMR2 TMR2
extern volatile int TMR2;
Which means in your main code, when you include a generic processor.h that delegates to the appropriate header for the target, you can detect features:
#include <processor.h>
#ifdef TMR2
x = TMR2;
#else
x = 0; // no timer, probably because we're on the cheaper model
#endif

Resources