Regarding chapter 22 Cross platform development of C Unleashed 
Author Message
 Regarding chapter 22 Cross platform development of C Unleashed

Hi there,

I was very interested in the concepts for cross-platform development
exposed in chapter 22 of C Unleashed. The idea is to define an
abstraction layer in portable ISO C that will be implemented for every
platform it needs to be ported to.
The example chosen in the book is that of networking. I will illustrate
my current issue with an example.
The networking interface designed in the chapter comprises the concept
of a "connection". On any given platform, a "connection" structure holds
the relevant non-portable data it needs to carry out its duty.
E.g. on Windows, we have the following definition:

#include "winsock.h"

struct cps_conn
{
     int address_length;
     SOCKADDR_IN local_addr;
     SOCKADDR_IN remote_addr;
     SOCKET socket;
     LPHOSTENT he;

Quote:
};

Now, wherever we use our portable networking library code, we have to
have a definition for our "connection", thus, we need to include the
header where the above definition lays, and thus indirectly include the
platform-specific header.

My issue raises from the fact that on the other hand, for my portable,
ISO C, code, I'd like to be able to use the strictest rules in my
compiler, like disabling language extensions. However, in every piece of
source relative to networking with my portable networking library, I
have to have a definition of my "connection", the struct cps_conn
structure, thus requiring the include of the platform specific header,
which of course is *highly* incompatable with the disabling of language
extensions.

So, I'd like to know if anyone would have any idea how to work this
issues around: idealy, I'd like platform specific, ISO-extended code in
the platform implementation of the portable library, and strict ISO C
code everywhere else in my code, including where I use the would-be
portable interface to my platform specific code.

--
Bertrand Mollinier Toublet
Currently looking for employment in the San Francisco Bay Area
http://www.*-*-*.com/



Fri, 12 Aug 2005 20:56:23 GMT  
 Regarding chapter 22 Cross platform development of C Unleashed
Quote:

> Hi there,

> I was very interested in the concepts for cross-platform development
> exposed in chapter 22 of C Unleashed. The idea is to define an
> abstraction layer in portable ISO C that will be implemented for every
> platform it needs to be ported to.
> The example chosen in the book is that of networking. I will illustrate
> my current issue with an example.
> The networking interface designed in the chapter comprises the concept
> of a "connection". On any given platform, a "connection" structure holds
> the relevant non-portable data it needs to carry out its duty.
> E.g. on Windows, we have the following definition:

> #include "winsock.h"

> struct cps_conn
> {
>     int address_length;
>     SOCKADDR_IN local_addr;
>     SOCKADDR_IN remote_addr;
>     SOCKET socket;
>     LPHOSTENT he;
> };

> Now, wherever we use our portable networking library code, we have to
> have a definition for our "connection", thus, we need to include the
> header where the above definition lays, and thus indirectly include the
> platform-specific header.

> My issue raises from the fact that on the other hand, for my portable,
> ISO C, code, I'd like to be able to use the strictest rules in my
> compiler, like disabling language extensions. However, in every piece of
> source relative to networking with my portable networking library, I
> have to have a definition of my "connection", the struct cps_conn
> structure, thus requiring the include of the platform specific header,
> which of course is *highly* incompatable with the disabling of language
> extensions.

> So, I'd like to know if anyone would have any idea how to work this
> issues around: idealy, I'd like platform specific, ISO-extended code in
> the platform implementation of the portable library, and strict ISO C
> code everywhere else in my code, including where I use the would-be
> portable interface to my platform specific code.

Actually, that's silly. Before I posted this, I had thought of trying
out the following way:

--- file cps.h ---

#ifndef CPS_H_
#define CPS_H_

struct cps_conn;

int cps_connect(struct cps_conn *);

#endif

--- end cps.h ---

--- file cps_win32.h ---

#ifndef CPS_WIN32_H_
#define CPS_WIN32_H_

#include "winsock.h"

struct cps_conn
{
   int address_length;
   SOCKADDR_IN local_addr;
   SOCKADDR_IN remote_addr;
   SOCKET socket;
   LPHOSTENT he;

Quote:
};

#endif

--- end cps_win32.h ---

and include both cps.h and cps_win32.h in my library implementation and
only cps.h in the rest of my code.
I had stupidly been put off guard by the following code somewhere in the
would-be portable code:

struct foo
{
   struct cps_conn connection;

Quote:
}

which of course could not be compiled without an explicit definition of
struct cps_conn.

The workaround is obviously
struct foo
{
   struct cps_conn *connection;

Quote:
}

I guess there really is no such thing as a free lunch. On the other
hand, I can totally put up with having only pointers to my non portable
structure wherever in my portable code.

IOW, problem solved ! Sorry for the noise...

--
Bertrand Mollinier Toublet
Currently looking for employment in the San Francisco Bay Area
http://bmt-online.dapleasurelounge.com/



Fri, 12 Aug 2005 21:43:57 GMT  
 Regarding chapter 22 Cross platform development of C Unleashed
in comp.lang.c i read:

Quote:
>I was very interested in the concepts for cross-platform development
>exposed in chapter 22 of C Unleashed. The idea is to define an
>abstraction layer in portable ISO C that will be implemented for every
>platform it needs to be ported to.

i don't own a copy of the book, so i'll just have to guess at what was
presented.  even if i don't match it exactly i'm fairly sure i'll have
the gist.

Quote:
>The networking interface designed in the chapter comprises the concept
>of a "connection". On any given platform, a "connection" structure
>holds the relevant non-portable data it needs to carry out its duty.
>E.g. on Windows, we have the following definition:

[some detailed window-y stuff]

Quote:
>Now, wherever we use our portable networking library code, we have to
>have a definition for our "connection", thus, we need to include the
>header where the above definition lays, and thus indirectly include
>the platform-specific header.

typically you use a pointer to an incomplete structure, which allows you to
hide the details from the iso conforming code, so:

  portable_networking.h:
    /* guards and other, usual, header fluff */

    typedef struct pn_netcon PN_NETCON;
    PN_NETCON * pn_open(const char *name, const char *mode);
    int pn_close(const PN_NETCON *connection);
    size_t pn_read(void *buf, size_t size, size_t n, PN_NETCON *connection);

    /* you should be thinking of stdio file streams by now */

the pn_netcon structure is incomplete, which makes it `opaque' from the
point of view of the portable code -- there are no members for them to
inspect, or worse to diddle.  the portable code must call the functions
defined by the api, receiving and/or passing only a pointer around, as that
is all that you are allowed to do with an incomplete struct.  each platform
has it's own implementation, which has a complete definition of the struct,
which contains whatever it needs, and which need not be the same size as
any other (though that is handy sometimes).

this is the c world's notion of an adt.

there is some, slight, danger in this technique, in that the portable code
might complete the structure, whether correct or not, which the compiler
will not complain about, in which case it's quite likely it will attempt to
diddle the content, which would cause problems.  but as with FILE * you
document that that is a no-no and leave the consequences undefined.
(surely you can attempt to cope e.g., keep a checksum or cryptographic hash
of the content as a member which is checked before any operation, but that
adds run-time expense, in time and storage, that may not be warranted.)

here's an example implementation, on a platform without networking support:

  #include "portable_networking.h"
  /* no need to complete the structure, but i will because most
     implementations would do so, hence i need at least one member */
  struct pn_netcon { int dummy; };

  /* open cannot succeed, return a null pointer */
  PN_NETCON * pn_open(const char *name, const char *mode)
  { return 0; }

  /* ignore close attempts, return a no-error indicator */
  int pn_close(const PN_NETCON *connection)
  { return 0; }

  /* read cannot succeed, return that nothing was read */
  size_t pn_read(void *buf, size_t size, size_t n, PN_NETCON *connection)
  { return 0; }

and here's an example usage (look familiar?):

  #include <stdio.h>
  #include "portable_networking.h"
  int main(void)
  {
    PN_NETCON *nc = pn_open("...", "r+");
    if (0 == nc) {
      fputs("error trying to open connection to ...\n", stderr);
      abort();
    }
    else
    {
      char buf[1000];
      size_t nr;
      while(0 < (nr = pn_read(buf, 1, sizeof buf, nc)))
      {
        /* do stuff with nr bytes */
      }
      /* probably there would be a pn_error and pn_eof so that you could
         test them here, just as you would for stdio file streams */
      if (0 != pn_close(nc)
      {
        fputs("error trying to close connection to ...\n", stderr);
        abort();
      }
    }
    return 0;
  }

--
bringing you boring signatures for 17 years



Fri, 12 Aug 2005 22:15:33 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Cross-Platform Development in C

2. Cross platform development strategy

3. Research survey on cross platform development

4. XVT Cross Platform Development

5. VC editor for cross platform development

6. Cross-platform development tools

7. Cross platform development (MetaWare HighC)

8. Cross-platform development (UNIX)

9. High-performance, cross-platform string support

10. slightly OT: cross-platform binary compatibility?

11. cross platform byte storage

 

 
Powered by phpBB® Forum Software