Author Topic: GCC: how to access a member of a struct in a union (of 4 structs) in a struct  (Read 1096 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...


Code: [Select]
/** A netconn descriptor */
struct netconn {
  /** type of the netconn (TCP, UDP or RAW) */
  enum netconn_type type;
  /** current state of the netconn */
  enum netconn_state state;
  /** the lwIP internal protocol control block */
  union {
    struct ip_pcb  *ip;
    struct tcp_pcb *tcp;
    struct udp_pcb *udp;
    struct raw_pcb *raw;
  } pcb;



I am trying to get hold of remote_ip.

Lots of examples online but none of them compile.

There is a union of four structs called ip tcp udp raw.

I've been trying e.g.       
uint32_t ipr;     
ipr = conn->pcb->ip->remote_ip;

but that one produces
error: invalid type argument of '->' (have 'union <anonymous>')

The actual remote_ip is ultimately defined (via about 5 more convolutions) as a uint32_t, and it contains the right value.

I avoid this convoluted stuff in my own code :)
« Last Edit: July 28, 2022, 01:25:15 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Quote
ipr = conn->pcb->ip->remote_ip;
Assuming conn is of type struct netconn*, the pointed object contains an actual pcb union, not a pointer to a pcb union.
Union members are accessed using the . operator (as are struct members).

So:
Quote
ipr = conn->pcb.ip->remote_ip;
should be what you are after.

In the debug screen capture, you can notice that there is not arrow close to pcb, as opposed to e.g. conn or ip.

Ref (C11): 6.5.2.3 Structure and union members, ยง1.

BTW: nothing to do with GCC in particular, just plain C.
« Last Edit: July 28, 2022, 01:41:56 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Unfortunately I had already tried that one.

error: incompatible types when assigning to type 'uint32_t' {aka 'long unsigned int'} from type 'ip_addr_t' {aka 'struct ip4_addr'}

Code: [Select]
/** This is the common part of all PCB types. It needs to be at the
   beginning of a PCB type definition. It is located here so that
   changes to this common part are made in one location instead of
   having to change all PCB structs. */
#define IP_PCB \
  /* ip addresses in network byte order */ \
  ip_addr_t local_ip; \
  ip_addr_t remote_ip; \
   /* Socket options */  \
  u8_t so_options;      \
   /* Type Of Service */ \
  u8_t tos;              \
  /* Time To Live */     \
  u8_t ttl               \
  /* link layer address resolution hint */ \
  IP_PCB_ADDRHINT

struct ip_pcb {
/* Common members of all PCB types */
  IP_PCB;
};


/** This is the aligned version of ip4_addr_t,
   used as local variable, on the stack, etc. */
struct ip4_addr {
  u32_t addr;
};

« Last Edit: July 28, 2022, 01:51:33 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Unfortunately I had already tried that one.

error: incompatible types when assigning to type 'uint32_t' {aka 'long unsigned int'} from type 'ip_addr_t' {aka 'struct ip4_addr'}
Ah, of course, I forgot to go on in the data structure, I only noticed the problem with . and ->.

Code: [Select]
    ipr = conn->pcb.ip->remote_ip.addr;
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: peter-h

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 3719
  • Country: us
Then you have to access the members of ip_addr_t to get the bytes / integer.  Since you didn't show that definition we can't tell you how to do that.
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Then you have to access the members of ip_addr_t to get the bytes / integer.  Since you didn't show that definition we can't tell you how to do that.
It's there, a bit hidden, in the picture...not so easy to spot from a phone. :-[
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
You are a genius, newbrain!

You can work for me anytime :) :) :)

Fate worse than death... I hear you say.

At my age, my brain can deal with just one level of indirection

ld l, (ix+0)
ld h, (ix+1)

I missed that too; I thought ipaddr_t was a uint32_t, which for ipv4 (which is all I am supporting) is just fine. Each byte is one of the four IP numbers.
« Last Edit: July 28, 2022, 02:17:24 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
I missed that too; I thought ipaddr_t was a uint32_t, which for ipv4 (which is all I am supporting) is just fine. Each byte is one of the four IP numbers.
It's probably just a union between a uint32_t addr and and something like uint8_t octects[4], so that one can access them separately (type punning guaranteed by the standard not to be UB, but caution with endianness).

Quote
Fate worse than death... I hear you say.
Let's just say it would be...interesting.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 3719
  • Country: us
I missed that too; I thought ipaddr_t was a uint32_t, which for ipv4 (which is all I am supporting) is just fine. Each byte is one of the four IP numbers.
It's probably just a union between a uint32_t addr and and something like uint8_t octects[4], so that one can access them separately (type punning guaranteed by the standard not to be UB, but caution with endianness).

Another reason to use a struct is that an IPv6 address can't fit in a single scalar type.  By making it a struct you can use assignment syntax to copy an address without an explicit call to memcpy.  If you are going to use a struct ipv6_addr_t you probably want to use a struct ipv4_addr_t for symmetry and so you can use macros to access them in the same way.  Most of the type you treat an ip address as a black box and don't access it's numerical value which is often stored in network byte order instead of host byte order, so the extra level of indirection to get to the integer representation doesn't usually matter.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Yes indeed; IPV6 is a compilation option of LWIP. In this project it is disabled because it is more work in other areas, and is generally (!) rarely used.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf