C语言中各种数据类型的长度 sizeof char, short, int, long, long long

这篇博客探讨了C语言中不同数据类型的长度,如char, short, int, long和long long,指出其长度取决于编译器和操作系统。在32位系统中,ILP32模型中它们的长度分别为1, 2, 4, 4字节,而64位系统遵循LP64模型,int为4字节,long和指针为8字节。文章还讨论了数据模型(LP64和ILP32)、字节对齐以及float和double的存储表示。" 112269908,10293020,GPIO工作模式详解与STM32配置实例,"['嵌入式开发', '微控制器', 'STM32', 'GPIO接口']
AI助手已提取文章相关产品:

这些数据类型的sizeof具体长度依赖于编译器和操作系统(32-bit or 64-bit)

 

1: 首先,参见c99标准

标准中没有定义这些数据类型的长度,而是定义了这些数据类型能表达的大小范围的最小极限。


C99链接: http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf


The C++ standard does not specify the size of integral types in bytes, but it specifies minimum ranges they must be able to hold. You can infer minimum size in bits from the required range and the value of CHAR_BIT macro, that defines the number of bits in a byte (in all but the most obscure platforms it's 8).

One additional constraint for char is that its size is always 1 byte, or CHAR_BIT bits (hence the name).

Minimum ranges required by the standard (page 22) are:

signed char: -127 to 127 (note, not -128 to 127; this accommodates 1's-complement platforms)
unsigned char: 0 to 255
"plain" char: -127 to 127 or 0 to 255 (depends on default char signedness)
signed short: -32767 to 32767
unsigned short: 0 to 65535
signed int: -32767 to 32767
unsigned int: 0 to 65535
signed long: -2147483647 to 2147483647
unsigned long: 0 to 4294967295
signed long long: -9223372036854775807 to 9223372036854775807
unsigned long long: 0 to 18446744073709551615
A C++ (or C) implementation can define the size of a type in bytes sizeof(type) to any value, as long as

the expression sizeof(type) * CHAR_BIT evaluates to the number of bits enough to contain required ranges, and
the ordering of type is still valid (e.g. sizeof(int) <= sizeof(long)).
The actual implementation-specific ranges can be found in <limits.h> header in C, or <climits> in C++ (or even better, templated std::numeric_limits in <limits> header). 
 


2: 数据类型长度需要符合2个标准


一个是数据类型能描述的范围,一个是数据类型表达范围之间的顺序


C90 standard requires that

sizeof(short) <= sizeof(int) <= sizeof(long)

C99 standard requires that

sizeof(short) <= sizeof(int) <= sizeof(long) < sizeof(long long)


3: 5种标准数据类型和他们的衍生类型


signed char

short int

int

long int

long long int


There are five standard signed integer types : signed char, short int, int, long int, and long long int. In this list, each type provides at least as much storage as those preceding it in the list.

For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type: unsigned char, unsigned short int, unsigned int, unsigned long int, and unsigned long long int, each of which occupies the same amount of storage and has the same alignment requirements. 

The C++ Standard says it like this :

3.9.1, §2 :

There are five signed integer types : "signed char", "short int", "int", "long int", and "long long int". In this list, each type provides at least as much storage as those preceding it in the list. Plain ints have the natural size suggested by the architecture of the execution environment (44); the other signed integer types are provided to meet special needs.

(44) that is, large enough to contain any value in the range of INT_MIN and INT_MAX, as defined in the header <climits>.

The conclusion : it depends on which architecture you're working on. Any other assumption is false.



4: 实践中的事实标准


32-bit 操作系统中,事实标准为 ILP32,  int, long, pointer 都是4字节

64-bit 操作系统中,事实标准为LP64, int - 4字节, long, pointer 是8字节

 在linux操作系统中,参见头文件 int-ll64.h

For 32-bit systems, the 'de facto' standard is ILP32 - that is, int, long and pointer are all 32-bit quantities.

For 64-bit systems, the primary Unix 'de facto' standard is LP64 - long and pointer are 64-bit (but int is 32-bit). The Windows 64-bit standard is LLP64 - long long and pointer are 64-bit (but long and int are both 32-bit).

At one time, some Unix systems used an ILP64 organization.

None of these de facto standards is legislated by the C standard (ISO/IEC 9899:1999), but all are permitted by it. 


5: 数据模型 LP64和ILP32

数据来源: http://en.wikipedia.org/wiki/64-bit#64-bit_data_models


Data model short (integer) int long (integer) long long pointers/
size_t
Sample operating systems
LLP64/
IL32P64
1632326464Microsoft Windows (X64/IA-64)
LP64/
I32LP64
1632646464Most Unix and Unix-like systems, e.g. SolarisLinuxBSD, and OS Xz/OS

数据来源:http://docs.oracle.com/cd/E19620-01/805-3024/lp64-1/index.html

Table F-1 C Data Type Sizes

C Type 

ILP32 

LP64 

char 

short 

16 

16 

int 

32 

32 

long  

32

64

long long 

64 

64 

pointer 

32

64

In addition to the data model changes, some system-derived types, such as size_t, have been expanded to be 64-bit quantities when 

compiled in the 64-bit environment.


数据来源: http://publib.boulder.ibm.com/infocenter/zvm/v6r2/index.jsp?topic=%2Fcom.ibm.zos.r12.cbcpx01%2Fdatatypesize64.htm

同上


6: linux 中的实际使用


#ifndef __ASSEMBLY__
/*
 * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
 * header files exported to user space
 */

typedef __signed__ char __s8;
typedef unsigned char __u8;

typedef __signed__ short __s16;
typedef unsigned short __u16;

typedef __signed__ int __s32;
typedef unsigned int __u32;

#ifdef __GNUC__
__extension__ typedef __signed__ long long __s64;
__extension__ typedef unsigned long long __u64;
#else
typedef __signed__ long long __s64;
typedef unsigned long long __u64;
#endif

也就是没用到long 类型,用了char, short, int, long long 就够了。

sizeof (void *) == sizeof (long)

数据类型分为三种

C standard  (var)

constant

subsystem 

7. printf

http://www.gnu.org/software/libc/manual/html_mono/libc.html#Integer-Conversions

12.12.4 Integer Conversions

This section describes the options for the ‘%d’, ‘%i’, ‘%o’, ‘%u’, ‘%x’, and ‘%X’ conversion specifications. These conversions print integers in various formats.

The ‘%d’ and ‘%i’ conversion specifications both print an int argument as a signed decimal number; while ‘%o’, ‘%u’, and ‘%x’ print the argument as an unsigned octal, decimal, or hexadecimal number (respectively). The ‘%X’ conversion specification is just like ‘%x’ except that it uses the characters ‘ABCDEF’ as digits instead of ‘abcdef’.

‘l’
Specifies that the argument is a long int or unsigned long int, as appropriate. Two ‘l’ characters is like the ‘L’ modifier, below.
If used with ‘%c’ or ‘%s’ the corresponding parameter is considered as a wide character or wide character string respectively. This use of ‘l’ was introduced in Amendment 1 to ISO C90. 

‘L’
‘ll’
‘q’
Specifies that the argument is a long long int. (This type is an extension supported by the GNU C compiler. On systems that don't support extra-long integers, this is the same as long int.)
The ‘q’ modifier is another name for the same thing, which comes from 4.4 BSD; a long long int is sometimes called a “quad” int. 

8: 字节对齐


http://publib.boulder.ibm.com/infocenter/zvm/v6r2/index.jsp?topic=%2Fcom.ibm.zos.r12.cbcpx01%2Fcbcpg1b0233.htm

http://publib.boulder.ibm.com/infocenter/zvm/v6r2/index.jsp?topic=%2Fcom.ibm.zos.r12.cbcpx01%2Fcbcpg1b0228.htm

http://www.unix.org/whitepapers/64bit.html

http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture

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

http://csweapon.diandian.com/post/2011-08-26/4372667


自然对齐

 64-bit operating environment

  • Align 8-bit data at any address
  • Align 16-bit data to be contained within an aligned four-byte word
  • Align 32-bit data so that its base address is a multiple of four
  • Align 64-bit data so that its base address is a multiple of eight
  • Align 80-bit data so that its base address is a multiple of sixteen
  • Align 128-bit data so that its base address is a multiple of sixteen
 An attempt to share pointers between 32-bit and 64-bit processes
Attention:
Source:
#include <stdio.h>
#include <stddef.h>
int main()
{
    struct T {
        char c;
        int *p;
        short s;
        } t;
        printf("sizeof(t) = %d\n", sizeof(t));
        printf("offsetof(t, c) = %d sizeof(c) = %d\n",
    offsetof(struct T, c), sizeof(t.c));
    printf("offsetof(t, p) = %d sizeof(p) = %d\n",
    offsetof(struct T, p), sizeof(t.p));
    printf("offsetof(t, s) = %d sizeof(s) = %d\n",
    offsetof(struct T, s), sizeof(t.s));
}
ILP32 output:
sizeof(t) = 12
offsetof(t, c) = 0 sizeof(c) = 1
offsetof(t, p) = 4 sizeof(p) = 4
offsetof(t, s) = 8 sizeof(s) = 2
LP64 output:
sizeof(t) = 24
offsetof(t, c) = 0 sizeof(c) = 1
offsetof(t, p) = 8 sizeof(p) = 8
offsetof(t, s) = 16 sizeof(s) = 2


Comparison of data structure member lengths produced from the same code
Source:
#include <stdio.h>

int main(void) {
    struct li{
             long la;
             int ia;
             } li;
    struct lii{
              long la;
              int ia;
              int ib;
              } lii;
    struct ili{
              int ia;
              long la;
              int ib;
              } ili;
    printf("length li = %d\n",sizeof(li));
    printf("length lii = %d\n",sizeof(lii));
    printf("length ili = %d\n",sizeof(ili));
}
ILP32 member lengths:
length li = 8   
length lii = 12 
length ili = 12 
LP64 member lengths:
length li = 16  
length lii = 16 
length ili = 24 

9: float double


In main storage and in disk storage, a float is represented with a 32-bit pattern and a double is represented with a 64-bit pattern.

Floating Point Primitive Data Types
TypeSizeRange
float32 bits-3.4E+38 to +3.4E+38
double64 bits-1.7E+308 to 1.7E+308




                

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值