简体   繁体   中英

how values are stored in different data types in c

I want to know how data types are stored in c, so i wrote a program to check how values are stored. when i saw the output i couldn't understand how different data typed store values in memory.

here is the program i tried,

#include <stdio.h>

int main() {
    int x;
    int valI, i;
    short valS;
    long valL;
    signed valSi;
    unsigned valUn;

    // printf("enter a num");
    // scanf("%d",&x);

    x = -10;
    valI = x;
    valS = x;
    valL = x;
    valSi = x;
    valUn = x;


    printf("\n\t%i\t%li\n",valI,sizeof(valI));

    for(i = 8*sizeof(valI); i >= 0 ; i--)
    {
        printf("%i",(valI & (1<<i))? 1 : 0);
    }


    printf("\n\t%i\t%li\n",valS,sizeof(valS));

    for(i = 8*sizeof(valS); i >= 0 ; i--)
    {
        printf("%i",(valS & (1<<i))? 1 : 0);
    }

    printf("\n\t%li\t%li\n",valL,sizeof(valL));

    for(i = 8*sizeof(valL); i >= 0 ; i--)
    {
        printf("%i",(valL & (1<<i))? 1 : 0);
    }

    printf("\n\t%i\t%li\n",valSi,sizeof(valSi));

    for(i = 8*sizeof(valSi); i >= 0 ; i--)
    {
        printf("%i",(valSi & (1<<i))? 1 : 0);
    }

    printf("\n\t%i\t%li\n",valUn,sizeof(valUn));

    for(i = 8*sizeof(valUn); i >= 0 ; i--)
    {
            printf("%i",(valUn & (1<<i))? 1 : 0);
    } 

    printf("\n\n");
}

the output for input = 10

enter a num10

    10      4

000000000000000000000000000001010

    10      2

00000000000001010

    10      8

00000000000000000000000000000101000000000000000000000000000001010

    10      4

000000000000000000000000000001010

    10      4

000000000000000000000000000001010

the output for input = -10

enter a num-10

    -10     4

011111111111111111111111111110110

    -10     2

11111111111110110

    -10     8

01111111111111111111111111111011011111111111111111111111111110110

    -10     4

011111111111111111111111111110110

    -10     4

011111111111111111111111111110110

can someone explain why this is happening? & how different datatypes store values in memory? thanks in advance

I want to know how data types are stored in C

Pedantically, that has no sense. How the data is stored is an implementation detail (and the C99 or C11 standard does not define how data is stored), and in principle you should not bother and try to write portable code .

Practically, how data is stored and represented, and how it is transmitted in function calls etc..., is specified in a document called Application Binary Interface . These conventions are specific to a processor and often to an operating system and followed by the compiler (and other tools).

Notice that some data might not be in memory, but eg only in a register.

You might read wikipages on two's complement , instruction sets , x86 , calling conventions , x86 calling conventions , processor registers , address space , virtual memory , endianness , data-structure alignment , integer (computer science) , floating point , IEEE floating point , ....

For x86-64 Linux you could read its ABI spec .

In practice, data representation is strongly machine & system specific. It is different on your ARM / Android tablet and on your Linux / x86-64 desktop and on your Arduino kit or an IBM System Z mainframe (so your program would give different results on these).

Notice that C99 gives you <stdint.h> with standard types like int32_t , uint64_t , intptr_t

If you care about interoperability , read more about serialization and favor well-defined textual formats (like eg JSON ).

Your positive numbers and unsigned numbers are represented as standart binary, with the unused bits filled with 0s.

Negative numbers in signed variables are stored in a two's-complement . Have a read, its a basic concept in computer science.

Basicly, a twos complement is a way of representing a negative value in binary.

As example, -10 is

011111111111111111111111111110110

In a two's complement of 32 bits. You can find out a two's complement for a given negative number like this:

-10:

First, take the positive number in binary. for 10 this is

00000000000000000000000000001010

Now invert it (change all 0s to 1s and vice versa)

11111111111111111111111111110101

Now add a single 1 in normal addition.

11111111111111111111111111110110

and voila, you have the binary representation of -10 in a 32bit number.

Although, the exact way the values are stored is, as the other answer mentioned, up to the compiler to determine, as there are no set rules for it.

The storage requirements for any type depend on the underlying operating system and hardware. There are significant differences between x86_64 and x86 storage sizes. You can use a slightly different version to do essentially what you have started out to do. For example:

#include <stdio.h>

#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

#ifndef CHAR_BIT
#define CHAR_BIT  8
#endif

/* signed data type low storage limit */
long long limit_s_low (unsigned char bytes)
{   return -(1ULL << (bytes * CHAR_BIT - 1)); }

/* signed data type high storage limit */
long long limit_s_high (unsigned char bytes)
{   return (1ULL << (bytes * CHAR_BIT - 1)) - 1; }

/* unsigned data type high storage limit */
unsigned long long limit_u_high (unsigned char bytes)
{
    if (bytes < sizeof (long long))
        return (1ULL << (bytes * CHAR_BIT)) - 1;
    else
        return ~1ULL - 1;
}

int main (void) {

#ifdef BUILD_64
    printf ("\n data type sizes for x86_64:\n\n");

    printf ("  sizeof (char)       : %lu\n", sizeof (char));
    printf ("  sizeof (char*)      : %lu  (all pointers)\n", sizeof (char*));
    printf ("  sizeof (short)      : %lu\n", sizeof (short));
    printf ("  sizeof (int)        : %lu\n", sizeof (int));
    printf ("  sizeof (long)       : %lu\n", sizeof (long));
    printf ("  sizeof (long long)  : %lu\n\n", sizeof (long long));
#else
    printf ("\n data type sizes for x86 (32-bit) :\n\n");

    printf ("  sizeof (char)       : %u\n", sizeof (char));
    printf ("  sizeof (char*)      : %u  (all pointers)\n", sizeof (char*));
    printf ("  sizeof (short)      : %u\n", sizeof (short));
    printf ("  sizeof (int)        : %u\n", sizeof (int));
    printf ("  sizeof (long)       : %u\n", sizeof (long));
    printf ("  sizeof (long long)  : %u\n\n", sizeof (long long));
#endif

#ifdef BUILD_64
    printf (" data type storage sizes for x86_64:\n\n");
#else
    printf (" data type storage sizes for x86:\n\n");
#endif

    printf ("  char - signed       : %11lld  to  %lld\n",
            limit_s_low (sizeof (char)), limit_s_high (sizeof (char)));
    printf ("  char - unsigned     : %11d  to  %llu\n",
            0, limit_u_high (sizeof (char)));
    printf ("  short - signed      : %11lld  to  %lld\n",
            limit_s_low (sizeof (short)), limit_s_high (sizeof (short)));
    printf ("  short - unsigned    : %11d  to  %llu\n",
            0, limit_u_high (sizeof (short)));
#ifdef BUILD_64
    printf ("  int - signed        : %lld  to  %lld\n",
            limit_s_low (sizeof (int)), limit_s_high (sizeof (int)));
    printf ("  int - unsigned      : %11d  to  %llu\n",
            0, limit_u_high (sizeof (int)));
    printf ("  (l)long - signed    : %.4e  to  %.4e\n",
            (double)limit_s_low (sizeof (long)), 
            (double)limit_s_high (sizeof (long)));
    printf ("  (l)long - unsigned  : %11d  to  %.4e  %llu\n\n",
            0, (double)limit_u_high (sizeof (long)), 
            limit_u_high (sizeof (long long)));
#else
    printf ("  int/long - signed   : %lld  to  %lld\n",
            limit_s_low (sizeof (int)), limit_s_high (sizeof (int)));
    printf ("  int/long - unsigned : %11d  to  %llu\n",
            0, limit_u_high (sizeof (int)));
    printf ("  llong   - signed    : %.4e  to  %.4e\n",
            (double)limit_s_low (sizeof (long long)), 
            (double)limit_s_high (sizeof (long long)));
    printf ("  llong - unsigned    : %11d  to  %.4e  %llu\n\n",
            0, (double)limit_u_high (sizeof (long long)), 
            limit_u_high (sizeof (long long)));
#endif

    return 0;
}

The #if defined(__LP64__) || defined(_LP64) #if defined(__LP64__) || defined(_LP64) block test whether the system is running x86_64 , if not, then defaults to assessing storage sizes for x86 . It is equally compilable/runable on x86 . On x86_64 , you will generally see the following:

Output

$ ./bin/typesize

 data type sizes for x86_64:

  sizeof (char)       : 1
  sizeof (char*)      : 8  (all pointers)
  sizeof (short)      : 2
  sizeof (int)        : 4
  sizeof (long)       : 8
  sizeof (long long)  : 8

 data type storage sizes for x86_64:

  char - signed       :        -128  to  127
  char - unsigned     :           0  to  255
  short - signed      :      -32768  to  32767
  short - unsigned    :           0  to  65535
  int - signed        : -2147483648  to  2147483647
  int - unsigned      :           0  to  4294967295
  (l)long - signed    : -9.2234e+18  to  9.2234e+18
  (l)long - unsigned  :           0  to  1.8447e+19  18446744073709551613

On a 32-bit box, the output would be:

$ ./datatype/typecast/bin/typesize_32

 data type sizes for x86 (32-bit) :

  sizeof (char)       : 1
  sizeof (char*)      : 4  (all pointers)
  sizeof (short)      : 2
  sizeof (int)        : 4
  sizeof (long)       : 4
  sizeof (long long)  : 8

 data type storage sizes for x86:

  char - signed       :        -128  to  127
  char - unsigned     :           0  to  255
  short - signed      :      -32768  to  32767
  short - unsigned    :           0  to  65535
  int/long - signed   : -2147483648  to  2147483647
  int/long - unsigned :           0  to  4294967295
  llong   - signed    : -9.2234e+18  to  9.2234e+18
  llong - unsigned    :           0  to  1.8447e+19  18446744073709551613

Let me know if you have any questions or would like additional help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM