Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #22867 > unrolled thread

struct with one member: padding?

Started by"Mark" <mark_cruzNOTFORSPAM@hotmail.com>
First post2012-06-27 12:33 -0400
Last post2012-06-27 18:03 -0700
Articles 8 — 8 participants

Back to article view | Back to comp.lang.c


Contents

  struct with one member: padding? "Mark" <mark_cruzNOTFORSPAM@hotmail.com> - 2012-06-27 12:33 -0400
    Re: struct with one member: padding? John Gordon <gordon@panix.com> - 2012-06-27 16:40 +0000
      Re: struct with one member: padding? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-06-27 18:27 +0100
    Re: struct with one member: padding? Ben Pfaff <blp@cs.stanford.edu> - 2012-06-27 09:57 -0700
    Re: struct with one member: padding? China Blue Meanies <chine.bleu@yahoo.com> - 2012-06-27 12:15 -0700
      Re: struct with one member: padding? Andrew Cooper <amc96@cam.ac.uk> - 2012-06-27 22:52 +0100
        Re: struct with one member: padding? scott@slp53.sl.home (Scott Lurndal) - 2012-06-27 23:42 +0000
    Re: struct with one member: padding? William Ahern <william@wilbur.25thandClement.com> - 2012-06-27 18:03 -0700

#22867 — struct with one member: padding?

From"Mark" <mark_cruzNOTFORSPAM@hotmail.com>
Date2012-06-27 12:33 -0400
Subjectstruct with one member: padding?
Message-ID<jsfckr$drq$1@speranza.aioe.org>
Hello

on many (all?) unix implementations IP address structure is designed this 
way:

struct in_addr
  {
     unsigned long s_addr;
  };

Does the Standard allow a C comiler to add padding in such structure? If it 
so, then we have to always 'memset' in_addr to 0 before use.

Thanks.

Mark 

[toc] | [next] | [standalone]


#22869

FromJohn Gordon <gordon@panix.com>
Date2012-06-27 16:40 +0000
Message-ID<jsfd2q$r2u$1@reader1.panix.com>
In reply to#22867
In <jsfckr$drq$1@speranza.aioe.org> "Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:

> struct in_addr
>   {
>      unsigned long s_addr;
>   };

> Does the Standard allow a C comiler to add padding in such structure? If it 
> so, then we have to always 'memset' in_addr to 0 before use.

If you're accessing in_addr.s_addr, why do you care if there is padding
before or after?

If you're trying to access in_addr as though it were not a struct I can
see why you would care, but that seems to be a pretty egregious error.

-- 
John Gordon                   A is for Amy, who fell down the stairs
gordon@panix.com              B is for Basil, assaulted by bears
                                -- Edward Gorey, "The Gashlycrumb Tinies"

[toc] | [prev] | [next] | [standalone]


#22873

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-06-27 18:27 +0100
Message-ID<0.c0f7244cec4de6609095.20120627182742BST.87k3yshdgx.fsf@bsb.me.uk>
In reply to#22869
John Gordon <gordon@panix.com> writes:

> In <jsfckr$drq$1@speranza.aioe.org> "Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:
>
>> struct in_addr
>>   {
>>      unsigned long s_addr;
>>   };
>
>> Does the Standard allow a C comiler to add padding in such structure? If it 
>> so, then we have to always 'memset' in_addr to 0 before use.
>
> If you're accessing in_addr.s_addr, why do you care if there is padding
> before or after?
>
> If you're trying to access in_addr as though it were not a struct I can
> see why you would care, but that seems to be a pretty egregious error.

I think that depends how you do it.

It's probably worth pointing out that there can't be any padding before
s_addr, only after.  I.e. sizeof (struct in_addr) may be greater than
sizeof (long) but

  struct in_addr a;
  assert((void *)&a == (void *)&a.s_addr);

can't fail.  Thus

  unsigned char bytes[sizeof (long)];
  memcpy(bytes, &a, sizeof bytes);

kind of fits your "access in_addr as though it were not a struct" but it's
safe.

None the less, I agree that the question hints that something dangerous
might be being considered!

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#22871

FromBen Pfaff <blp@cs.stanford.edu>
Date2012-06-27 09:57 -0700
Message-ID<87bok4wv44.fsf@blp.benpfaff.org>
In reply to#22867
"Mark" <mark_cruzNOTFORSPAM@hotmail.com> writes:

> on many (all?) unix implementations IP address structure is designed this 
> way:
>
> struct in_addr
>   {
>      unsigned long s_addr;
>   };
>
> Does the Standard allow a C comiler to add padding in such
> structure?

Yes.  (I don't know of any implementations that will.)

[toc] | [prev] | [next] | [standalone]


#22889

FromChina Blue Meanies <chine.bleu@yahoo.com>
Date2012-06-27 12:15 -0700
Message-ID<chine.bleu-59CFD2.12151527062012@news.eternal-september.org>
In reply to#22867
In article <jsfckr$drq$1@speranza.aioe.org>,
 "Mark" <mark_cruzNOTFORSPAM@hotmail.com> wrote:

> Hello
> 
> on many (all?) unix implementations IP address structure is designed this 
> way:
> 
> struct in_addr
>   {
>      unsigned long s_addr;
>   };
> 
> Does the Standard allow a C comiler to add padding in such structure? If it 
> so, then we have to always 'memset' in_addr to 0 before use.

Given
        struct in_addr variable;
then
        &variable == &(variable.s_addr)
however
        sizeof(variable) =?= sizeof(variable.s_addr)

You can't make any safe portable assumptions about the sizeof the struct and 
any/all of its fields.

In practice any CPU you're likely to use will not pad an unsigned long. If you 
want to restrict your software to such machines, you're not going to lose too 
many customers.

For my code I run a small program as part of the build which does like
    int main(int argc, cahr**argv) {
        FILE *f = fopen("sizes.h", "w");
        fprintf(f,"#define size_unsigned_long %d\n", sizeof(unsigned long));
        fprintf(f,"#define size_time_t %d\n", sizeof(time_t));
        fprintf(f,"#define size_struct_in_addr %d\n", sizeof(struct in_addr));
        ...
        return 0
    }

Then you can do things like
    #include "sizes.h"
    #if size_unsigned_long!=size_struct_in_addr
        #error Cannot compile: sizeof(unsigned long)!=sizeof(struct in_addr)
    #endif

-- 
My name Indigo Montoya.      |                     The Dude abides.
You flamed my father.        |       I'm whoever you want me to be.
Prepare to be spanked.       |  Annoying Usenet one post at a time.
Stop posting that!           |    At least I can stay in character.

[toc] | [prev] | [next] | [standalone]


#22901

FromAndrew Cooper <amc96@cam.ac.uk>
Date2012-06-27 22:52 +0100
Message-ID<dgLGr.338518$C_6.224852@fx28.am4>
In reply to#22889
On 27/06/2012 20:15, China Blue Meanies wrote:
> In article <jsfckr$drq$1@speranza.aioe.org>,
>  "Mark" <mark_cruzNOTFORSPAM@hotmail.com> wrote:
> 
>> Hello
>>
>> on many (all?) unix implementations IP address structure is designed this 
>> way:
>>
>> struct in_addr
>>   {
>>      unsigned long s_addr;
>>   };
>>
>> Does the Standard allow a C comiler to add padding in such structure? If it 
>> so, then we have to always 'memset' in_addr to 0 before use.
> 
> Given
>         struct in_addr variable;
> then
>         &variable == &(variable.s_addr)
> however
>         sizeof(variable) =?= sizeof(variable.s_addr)
> 
> You can't make any safe portable assumptions about the sizeof the struct and 
> any/all of its fields.
> 
> In practice any CPU you're likely to use will not pad an unsigned long. If you 
> want to restrict your software to such machines, you're not going to lose too 
> many customers.
> 
> For my code I run a small program as part of the build which does like
>     int main(int argc, cahr**argv) {
>         FILE *f = fopen("sizes.h", "w");
>         fprintf(f,"#define size_unsigned_long %d\n", sizeof(unsigned long));
>         fprintf(f,"#define size_time_t %d\n", sizeof(time_t));
>         fprintf(f,"#define size_struct_in_addr %d\n", sizeof(struct in_addr));
>         ...
>         return 0
>     }
> 
> Then you can do things like
>     #include "sizes.h"
>     #if size_unsigned_long!=size_struct_in_addr
>         #error Cannot compile: sizeof(unsigned long)!=sizeof(struct in_addr)
>     #endif
> 

There is a different way of doing this which does not rely on a
generated file (so no chance of going stale or missing), nor pollute the
defines with lower case characters.

#define BUILD_BUG_IF(condition) ((void)sizeof(struct {
int:-!!(condition); }))

at which point, your code becomes

BUILD_BUG_IF(sizeof(unsigned long) != sizeof(struct in_addr));

True, your error message then becomes "error: negative width in
bit-field ‘<anonymous>’" or similar, but you do get the file and line
number of the failure, which then allows anyone to see why compiling failed.

~Andrew

[toc] | [prev] | [next] | [standalone]


#22908

Fromscott@slp53.sl.home (Scott Lurndal)
Date2012-06-27 23:42 +0000
Message-ID<sTMGr.43373$0I1.319@news.usenetserver.com>
In reply to#22901
Andrew Cooper <amc96@cam.ac.uk> writes:
>On 27/06/2012 20:15, China Blue Meanies wrote:
>> In article <jsfckr$drq$1@speranza.aioe.org>,
>>  "Mark" <mark_cruzNOTFORSPAM@hotmail.com> wrote:
>> 
>>> Hello
>>>
>>> on many (all?) unix implementations IP address structure is designed this 
>>> way:
>>>
>>> struct in_addr
>>>   {
>>>      unsigned long s_addr;
>>>   };
>>>
>>> Does the Standard allow a C comiler to add padding in such structure? If it 
>>> so, then we have to always 'memset' in_addr to 0 before use.
>> 
>> Given
>>         struct in_addr variable;
>> then
>>         &variable == &(variable.s_addr)
>> however
>>         sizeof(variable) =?= sizeof(variable.s_addr)
>> 
>> You can't make any safe portable assumptions about the sizeof the struct and 
>> any/all of its fields.
>> 
>> In practice any CPU you're likely to use will not pad an unsigned long. If you 
>> want to restrict your software to such machines, you're not going to lose too 
>> many customers.
>> 
>> For my code I run a small program as part of the build which does like
>>     int main(int argc, cahr**argv) {
>>         FILE *f = fopen("sizes.h", "w");
>>         fprintf(f,"#define size_unsigned_long %d\n", sizeof(unsigned long));
>>         fprintf(f,"#define size_time_t %d\n", sizeof(time_t));
>>         fprintf(f,"#define size_struct_in_addr %d\n", sizeof(struct in_addr));
>>         ...
>>         return 0
>>     }
>> 
>> Then you can do things like
>>     #include "sizes.h"
>>     #if size_unsigned_long!=size_struct_in_addr
>>         #error Cannot compile: sizeof(unsigned long)!=sizeof(struct in_addr)
>>     #endif
>> 
>
>There is a different way of doing this which does not rely on a
>generated file (so no chance of going stale or missing), nor pollute the
>defines with lower case characters.
>
>#define BUILD_BUG_IF(condition) ((void)sizeof(struct {
>int:-!!(condition); }))
>
>at which point, your code becomes
>
>BUILD_BUG_IF(sizeof(unsigned long) != sizeof(struct in_addr));
>
>True, your error message then becomes "error: negative width in
>bit-field ‘<anonymous>’" or similar, but you do get the file and line
>number of the failure, which then allows anyone to see why compiling failed.
>

If your code depends on sizeof(struct in_addr) in any way, it's broken
by design.   There should be no need for an application to do anything
with the fields in in_addr, other than specific copy operations between
two in_addr structures.     There are library functions to modify or set
the correct values in this structure, for example:

    
 /*
  * Listen on all interfaces
  */

  self.sin_addr.s_addr = INADDR_ANY;

        /*
         * Translate a text hostname/dotted-quad to in_addr
         */
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_INET;
        hints.ai_socktype = SOCK_STREAM;
        diag = getaddrinfo(n_hostname, NULL, &hints, &res);
        if (diag != 0) {
            n_logger->log("%s Unable to determine"
                          " interface address for '%s': %s\n",
                          n_subsys, n_hostname, gai_strerror(diag));
            n_logger->log("%s  Using INADDR_ANY\n", n_subsys);
            self.sin_addr.s_addr = INADDR_ANY;
        } else {
            struct sockaddr_in *sinp = (struct sockaddr_in *)res->ai_addr;
            self.sin_addr.s_addr = sinp->sin_addr.s_addr;
        }

[toc] | [prev] | [next] | [standalone]


#22913

FromWilliam Ahern <william@wilbur.25thandClement.com>
Date2012-06-27 18:03 -0700
Message-ID<a3nsb9-3pf.ln1@wilbur.25thandClement.com>
In reply to#22867
In comp.unix.programmer Mark <mark_cruzNOTFORSPAM@hotmail.com> wrote:
> Hello

> on many (all?) unix implementations IP address structure is designed this
> way:

In 2012 there are IPv4 addresses and IPv6 addresses, and all extant systems
support both. Therefore, your statement is incorrect because struct in_addr
is no longer sufficient to store an IP address. Indeed, there is no standard
data structure to hold an IP address anymore, for better or worse. The
closest standard data structure is a struct sockaddr_storage.

If you need to manipulate IP addresses in non-trivial ways, it's probably
best to just define your own data structures.

> struct in_addr
>   {
>      unsigned long s_addr;
>   };

> Does the Standard allow a C comiler to add padding in such structure? If
> it so, then we have to always 'memset' in_addr to 0 before use.

There's no requirement that you must use memset. Assigning 0 to .s_addr
should suffice. In fact, I don't believe it's common to use memset that
way at all. You may be thinking of using memset to 0 initialize struct
sockaddr and cousins.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web