size of structure in c language

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am having a little problem understanding the structure in c language. I do not understand how memory allocate for structure

 

This is my code 

#include <stdio.h> 
struct S
{
    int x;
    char y;
}s1;
     
int main()
{
    s1.x = 20;
    s1.y ='A';
  
 printf("Size of Structure : %d byte \n", sizeof(struct S));
 printf("Size of s1 : %d byte \n", sizeof(s1));
 printf("Size of s1.x : %d  byte\n", sizeof(s1.x));
 printf("Size of s1.x : %d byte \n", sizeof(s1.y));
  
    return 0;
}

 

Size of Structure : 8 byte
Size of s1 : 8 byte
Size of s1.x : 4  byte
Size of s1.x : 1 byte

 

From the output it shows that the structure takes 8 bytes to store all data 

s1.x takes  4  byte
s1.x takes  1 byte

 

I don't understand how s1 takes 8 bytes because total size of structure is 8 bytes ?

 

 

This topic has a solution.
Last Edited: Thu. Feb 13, 2020 - 12:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVR's are 8 bit mpus, your structure consists of a two byte int and a one byte char, so total of three bytes.

Where did you run your code?   PC perhaps?

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

You are talking about building this on a PC/ARm and not an AVR aren't you ?

 

In AVR the sizeof(s1) will be 3. The int takes 2 bytes and the char takes 1 byte.

 

But on 32(+) bit micros not only will the int very likely be 4 bytes but also the processor finds it much quicker/easier to access single bytes by making a 4 byte aligned fetch and then just masking out the single byte it needs. So on a PC both the int and the char will be 4 bytes each though in the latter it will only actually USE one of the 4 bytes and the other three are purely for packing/alignment.

 

This is a VERY common issue in computer software because say I had:

struct S
{
    int x;
    char y;
}s1;

on my AVR and I set s1.x to 12345 and s1.y to 'X' then I use a for() loop to send all the bytes in sizeof(s1) to a PC then only 3 bytes will be read. Even though the receiving PC "knows" the layout of struct S as an int and a char it will apply a "PC layout" to the data. So if the received bytes are put into a plain "unsigned char" buffer and then a (struct S) interpretation is cast onto the data it will completely fail to read x or y correctly.

 

For this reason various other ways to transfer data (to keep the layout intact) have been invented when data passes from one place to another. One is XML, another is JSON, another is Google Protobufs.

 

Oh and it's not just size/packing/alignment that can cause issues here. There's also endianism. If I set a 2 byte int to 12345 the bytes stored are 0x30 and 0x39 but is that held as 0x30,0x39 or as 0x39,0x30 ? One side of a transmission might send the data (assuming the 2 byte size were agreed) as 0x3039 and one might send 0x3930. If they don't agree on endianism then it will be read as 14640 and not 12345 !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

PS forgot to say that various C compilers do usually offer ways to at least over-ride any alignment/packing that can at least help when they are trying to read data from a "foreign" data source (like an AVR). In MSVC for example there is:

#pragma pack(1)
struct S
{
    int x;
    char y;
}s1;

that will at least reduce s1 to 5 not 8 bytes.

 

For GCC you can try a few things. One is to build the code by passing -fpack-struct as a build option to the compiler. That makes all the structs in the code that is build use a packed layout. These days GCC also supports the same "#pramga pack(1)" as MSVC to try and be compatible with it. But it also offers 

__attribute__((packed))
struct S
{
    int x;
    char y;
}s1;

Again on GCC for a PC this should make sizeof(s1) 5 too.

 

But you still face the issue of an AVR creating 3 bytes and a PC creating 5 bytes. The way to overcome this is <stdint.h>. Never, ever use "int", "short", "long" in C code. Always use types from <stdint.h>. So if you use:

#include <stdint.h>

#pragma pack(1)
struct S
{
    int16_t x;
    char y;
}s1;

this will be three bytes on both AVR and PC. And if you use:

#include <stdint.h>

#pragma pack(1)
struct S
{
    int32_t x;
    char y;
}s1;

this will be 5 bytes on both. The stdint types instantly tell you how many bits (and hence bytes) they will use. An int32_t, unlike an "int" will always be a 32 bit (4 byte) variable wherever you use it.

 

The one base C type it's OK to use "as is" would be "char" but ONLY when you are using it to hold characters. If you are using it for 8 bit numbers (either unsigned 0..255 or signed -128..+127) then use either uint8_t or int8_t instead.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:
the processor finds it much quicker/easier to access single bytes by making a 4 byte aligned fetch

and, in some cases, it is required that data be aligned to certain boundaries - otherwise the processor will throw a wobbly (to use the technical term).

 

It's important to bear this in mind before trying to override the alignment/packing of your structs - this can lead to some very weird bugs & crashes if you're not very careful !

 

surprise

 

or so I'm told ... wink

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

sky33 wrote:
I am having a little problem understanding the structure in c language

Remember that set of links I gave you for 'C' learning & reference?

 

http://blog.antronics.co.uk/2011...

 

This is covered in the mentioned free online textbook:

The next issue is to consider what a structure looks like in terms of storage layout. It's best not to worry about this too much, but it is sometimes useful if you have to use C to access record-structured data written by other programs. The wp_char structure will be allocated storage as shown in Figure 6.1.

 

Diagram showing the layout of the values in 'struct wp_char',            with boxes containing 'wp_cval', an empty space of padding,            'wp_font' and 'wp_psize'.
Figure 6.1. Storage Layout of a Structure

 

The diagram assumes a number of things: that a char takes 1 byte of storage; that a short needs 2 bytes; and that shorts must be aligned on even byte addresses in this architecture. As a result the structure contains an unnamed 1-byte member inserted by the compiler for architectural reasons. Such addressing restrictions are quite common and can often result in structures containing ‘holes’.

The Standard makes some guarantees about the layout of structures and unions:

  • Members of a structure are allocated within the structure in the order of their appearance in the declaration and have ascending addresses.
  • There must not be any padding in front of the first member.
  • The address of a structure is the same as the address of its first member, provided that the appropriate cast is used. Given the previous declaration of struct wp_char, if item is of type struct wp_char, then (char *)item == &item.wp_cval.
  • Bit fields (see Section 6.4) don't actually have addresses, but are conceptually packed into units which obey the rules above.

 

 

https://publications.gbdirect.co.uk//c_book/chapter6/structures.html

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Never, ever use "int", "short", "long" in C code.
Never say "never".

A local loop variable from -300 to +300 should probably be int.

C's definition of "int" is not so vague as to be useless.

This is one use.

With a constant range, optimization would probably fix int64_t.

Fixing expressions might be harder.

 

On a platform with an 10-bit byte, signed char might be better,

but int16_t and int32_t would be unavailable.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


skeeve wrote:

Never say "never".

Not me. Them....

 

 

(OK so it is (advisory) not (required) but it's advice best heeded for the reasons they give).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Never say "never".

Ha ha - "rules are there to be broken".

 

But one does need to understand the rules to know when it's appropriate to break them ...

 

skeeve wrote:
On a platform with an 10-bit byte, signed char might be better,

but int16_t and int32_t would be unavailable.

Note that stdint does include other named types which specify other requirements than size ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
Where did you run your code?   PC perhaps?

 

clawson wrote:
You are talking about building this on a PC/ARm and not an AVR aren't you ?

 

yes I have tested code on the PC. I have used GCC compiler 

 

The device can be of any number of bits like 2 bit, 4 bit, 8 bit, 16 bit , 32 bit, 64 bit.  finally I am storing data in the device.    

 

assume machine is 64 bit,  I need to understand  how much memory, my program will occupy if I store data through a structure if it takes 8 bytes then s1 occupy 8 bytes 

 

 


 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

sky33 wrote:
I am having a little problem understanding the structure in c language

Remember that set of links I gave you for 'C' learning & reference?

 

http://blog.antronics.co.uk/2011...

 

This is covered in the mentioned free online textbook:

 

I have taken my full time to understand , only then I have asked question.  My question is why s1 is taking 8 bytes  ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sky33 wrote:
My question is why s1 is taking 8 bytes  ?

and that question has been answered - so time to mark the solution.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sky33 wrote:
I need to understand  how much memory, my program will occupy

You need to study the documentation for the particular compiler you are using.

 

In the 'C' programming language, some things are implementation defined - the sizes of the types is one such thing; padding / alignment is another.

 

These things will be in the documentation for the particular compiler - look for a section on "implementation-defined behaviour" or similar [1].

 

Also, you should get a map file when you build your project - and that will have details of memory usage.

 

EDIT

 

For AVR-GCC, the implementation details are here:

 

https://gcc.gnu.org/wiki/avr-gcc

 

Your PC version of GCC will be different - so you need to find the corresponding information for that particular version.

 

EDIT 2

 

[1] The AVR-GCC documentation (linked above) calls it "ABI",  for "Application Binary Interface" - so that's another term to look for ...

 

 

EDIT 3

 

Here's the info for MSVC:

 

https://docs.microsoft.com/en-us/cpp/c-language/implementation-defined-behavior?view=vs-2019

 

Specifically, the size of int:  https://docs.microsoft.com/en-us/cpp/c-language/range-of-integer-values?view=vs-2019

 

Structure padding & alignment:  https://docs.microsoft.com/en-us/cpp/c-language/padding-and-alignment-of-structure-members?view=vs-2019

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Feb 12, 2020 - 05:10 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

sky33 wrote:
assume machine is 64 bit,  I need to understand  how much memory, my program will occupy if I store data through a structure if it takes 8 bytes then s1 occupy 8 bytes 
If you are asking such a question you seem to have completely failed to to understand anything that was explained above?

 

For one thing use stdint.h types for more predictability about data sizes. A uint32_t will always be 4 bytes on whatever platform you use it in while an "int" might be 2, 4, 8 or some other number of bytes and it completely depends what you build it for and what some of the build options might be set to (I'm thinking of -mint8 for example with avr-gcc).

 

But also you should not be worrying about "layout" anyway. Just let the compiler/linker place things for your. If for their own needs they choose to "spread things out" then that is up to them.

 

All this only really becomes an issue if you ever want to transit (in binary form) a memory layout of some struct description created by one C compiler to be interpreted by some other C compiler (which may have chosen a different layout). There are two approaches to this - you can then either try and persuade one (or possibly even both) compilers to create the same layout using things like -fpack-struct, #pramga pack(), __attribute__((packed)) or a far more reliable mechanism is to extract all the data elements and send them in some "universal form" that is always guaranteed to be in the same layout. As I said above there are several of these - I just listed a few examples but you could perhaps use any of the following:

 

1) printf() into ASCII, s1.x=12345 might be stored in various ways by a compiler but if you sprintf(buff, "%d", s1.x) then transmit the "12345" this creates that's going to be the same for any compiler, at the receiving end convert it back with ssacnf()

 

2) Google Protobufs - the Google organisation own thousands and thousands of computer (probably millions in fact) and they have a need to pass data between them all the time but they can't be sure how any particular device might structure it's data. So they invented a mechanism called "Protobuf"s which is a re-coding of any data into a common format that they pass on their internal networks and then reconstruct into "local format" on receiving computers

 

3) in the same kind of vein JSON ("JavaScript Object Notation) was invented. As the name suggest this originated from the Javascript web programming language. When myriad devices access websites and take data from them there is an issue that they may each have different interpretations of the data. So JSON was invented so data could be delivered so as to always be delivered in a similar form to all devices

 

4) XML is a wider standard that was designed to be able to carry ANY kind of data in a common format that all readers could interpret the same way.

 

5) even "INI" files tend to be universally readable as they re-encode binary stuff into "human form" so that not only can humans read them but anything that mimics a human reading them can interpret the data in the same way.

 

6) there's actually tons more of such "protocols" for "unambiguous data transmission"

 

Bottom line: memory layout does not matter - the only exception to that is when you try and pass the entire layout "verbatim" (as it exists in binary form) from one place to another where the reader may not have the same interpretation of the data. If that's an issue you use a data re-encoding system to first put the data into a common/universal format before it is exchanged.

 

PS forgot to say that if you are interested in sizeof() have a look at what offsetof() does too !

Last Edited: Thu. Feb 13, 2020 - 09:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:
a far more reliable mechanism is to extract all the data elements and send them

This is known as Serialisation:

 

https://en.wikipedia.org/wiki/Serialization

 

Google Protobufs

For example, see: https://www.avrfreaks.net/forum/protobuf-google-protocol-buffers

 

there's actually tons more of such "protocols" for "unambiguous data transmission"

Some more examples here:

 

https://www.avrfreaks.net/forum/protocol-streaming-serial-data

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...