char、unsigned char、uint8_t、uint16_t

概述

  • 基础

在C/C++中,char用来定义字符型变量,只占一个字节(8位)。

C语言中如int、long、short等不指定signed或unsigned时都默认为signed,但char在标准中不指定为signed或unsigned,编译器可以编译为带符号的,也可以编译为不带符号的。

但是我感觉不指定signed或unsigned好像大多数是带符号的。

如果是带符号的,其取值范围为 -128 ~ +127(-27~27-1),符号占1位,其他占7位。

unsigned char 表示不带符号的,表示的范围是 0~255(0 ~ 2^8-1)

  • 取值范围

signed char: -2^7 ~ 2^7-1 unsigned char : 0 ~ 2^8-1

计算次方的函数pow( 2, 8)

  • 写法
char *a = "abcd";//无警告

signed char *b = "abcd";//编译报警告 ”Initializing 'signed char *' with an expression of type 'char [5]' converts between pointers to integer types with different sign”

unsigned char *c = "abcd"; //编译报警告 "Initializing 'unsigned char *' with an expression of type 'char [5]' converts between pointers to integer types with different sign"

编译警告是因为 *b 和 *c 分别使用signed和unsigned修饰char是integer类型的数据,后面赋值给的是char的字符串,所以报警告

  • 字符数组
char string[] = "abcd";
NSLog(@"%s",string);
  • 判断编译器默认char符号方法方法

判断编译器默认char符号方法方法(此方法来源于百度百科

char c = -1;
if(c < 200){  
    printf("signed\n");
}
else{
    printf("unsigned\n");
}

我的编译器报警告了,在第2行“Comparison of constant 200 with expression of type ‘char’ is always true“,Xcode的Clang编译器默认是带符号的,所以always true。

  • cont char
char string[] = "abc";
const char *run = string;

打印使用"%s"。

  • unsigned char
unsigned char uc = 100;
NSLog(@"uc %c",uc);  // -> d
NSString *str = [NSString stringWithFormat:@"%c",uc];
NSLog(@"str %@",str); // -> d

第一行的定义相当于

unsigned char uc = 'd';

打印使用"%c"。

转NSString

char -> NSString

//定义char类型的字符
char *a = "abcd";
//打印字符a
NSLog(@"char %s",a);
//将char类型转NSString类型
NSString *str = [NSString stringWithFormat:@"%s",a];
NSLog(@"string : %@",str);

char[] -> NSString

char string[] = "abcd";
NSLog(@"%s",string);
NSString *str = [NSString stringWithFormat:@"%s",string];
NSLog(@"string : %@",str);
  • 使用NSString的方法

[NSString stringWithUTF8String:(nonnull const char *)]

或者

[NSString stringWithCString:(nonnull const char *) encoding:(NSStringEncoding)]

入参都是const char *类型的,返回值都是NSString类型的。

char string[] = "abcd";
NSString *str = [NSString stringWithUTF8String:string];
NSLog(@"string : %@",str);
char *a = "abcd";
NSString *str = [NSString stringWithUTF8String:a];
NSLog(@"string : %@",str);

uint8_t、uint16_t

  • uint8_t

在iOS中的定义如下:

#ifndef _UINT8_T
#define _UINT8_T
typedef unsigned char uint8_t;
#endif /* _UINT8_T */

typedef unsigned char,定义了uint8_t是unsigned char类型的,可以解释为占8位的无符号的int型的整数。

实质上就是取值范围在0~225之间的整数。

  • uint16_t

在iOS中的定义:

#ifndef _UINT16_T
#define _UINT16_T
typedef unsigned short uint16_t;
#endif /* _UINT16_T */

unsigned short类型的。

取值范围初探

1个字节 = 8位(以二进制存储),理解字节和位数的关系有有助于理解数据在计算机中的存储。

32位的操作系统对应4个字节,64位对应8个字节,也就是说在32位操作系统上,计算机分配4个字节的内存来存储一个数据。

因为内存的字节数有限,所以存储的数据有限,所以不同类型的数据在计算机上存储是有范围的。

char

无符号取值范围:二进制为 00000000 ~ 11111111 ,有8位二进制数存储

char的取值范围是 0~255(0 ~ 2^8-1)

有符号取值范围:-2^7 ~ (2^7)-1 也就是-128 ~ 127,符号占一位。

int

  • 带符号的32位int

带符号的32位int整数的取值范围是 -2147483648(-2^31)~ 2147483647(2^31-1)

int max = pow(2, 31)-1; // -> 2147483647
int min = pow(-2, 31);  // -> -2147483648
NSLog(@"%d~%d",min,max);

我的电脑是32位的,当计算超出范围时,返回的值是最小值。

int max = pow(2, 100); // -> -2147483648
int min = pow(-2, 100);  // -> -2147483648
NSLog(@"%d~%d",min,max);

pow()这个函数里面肯定是做了处理了,所以程序没有直接闪退。

推荐阅读

  • 不带符号的32位int

0 ~ 2^32-1

取值范围的计算方法

sizeof()

int result_int = sizeof(int);
NSLog(@"%d",result_int);// -> 4

int result_f = sizeof(float);
NSLog(@"%d",result_f);// -> 4

int result_char = sizeof(char);
NSLog(@"%d",result_char);// -> 1

int result_uint8_t = sizeof(uint8_t);
NSLog(@"%d",result_uint8_t);// -> 1

int result_uint16_t = sizeof(uint16_t);
NSLog(@"%d",result_uint16_t);// -> 2

int result_uint32_t = sizeof(uint32_t);
NSLog(@"%d",result_uint32_t);// -> 4

int result_uint64_t = sizeof(uint64_t);
NSLog(@"%d",result_uint64_t);// -> 8

1个字节 = 8位

一些系统的宏

iOS提供了一些宏,可以直接获取某些数据类型的取值范围

/* C90/99 5.2.4.2.1 */
#define SCHAR_MAX __SCHAR_MAX__
#define SHRT_MAX  __SHRT_MAX__
#define INT_MAX   __INT_MAX__
#define LONG_MAX  __LONG_MAX__

#define SCHAR_MIN (-__SCHAR_MAX__-1)
#define SHRT_MIN  (-__SHRT_MAX__ -1)
#define INT_MIN   (-__INT_MAX__  -1)
#define LONG_MIN  (-__LONG_MAX__ -1L)

#define UCHAR_MAX (__SCHAR_MAX__*2  +1)
#define USHRT_MAX (__SHRT_MAX__ *2  +1)
#define UINT_MAX  (__INT_MAX__  *2U +1U)
#define ULONG_MAX (__LONG_MAX__ *2UL+1UL)

#ifndef MB_LEN_MAX
#define MB_LEN_MAX 1
#endif

#define CHAR_BIT  __CHAR_BIT__

#ifdef __CHAR_UNSIGNED__  /* -funsigned-char */
#define CHAR_MIN 0
#define CHAR_MAX UCHAR_MAX
#else
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX __SCHAR_MAX__
#endif

/* C99 5.2.4.2.1: Added long long.
   C++11 18.3.3.2: same contents as the Standard C Library header <limits.h>.
 */
#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L

#undef  LLONG_MIN
#undef  LLONG_MAX
#undef  ULLONG_MAX

#define LLONG_MAX  __LONG_LONG_MAX__
#define LLONG_MIN  (-__LONG_LONG_MAX__-1LL)
#define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL)
#endif

关于int的一些宏

/* 7.18.2.1 Limits of exact-width integer types */
#define INT8_MAX         127          
#define INT16_MAX        32767         
#define INT32_MAX        2147483647     //有符号的32位int型数据的最大值
#define INT64_MAX        9223372036854775807LL 

#define INT8_MIN          -128           
#define INT16_MIN         -32768         
   /*
      Note:  the literal "most negative int" cannot be written in C --
      the rules in the standard (section 6.4.4.1 in C99) will give it
      an unsigned type, so INT32_MIN (and the most negative member of
      any larger signed type) must be written via a constant expression.
   */
#define INT32_MIN        (-INT32_MAX-1)    //有符号的32位int型数据的最小值
#define INT64_MIN        (-INT64_MAX-1)    

#define UINT8_MAX         255
#define UINT16_MAX        65535
#define UINT32_MAX        4294967295U      //无符号的32位int型数据的最大值
#define UINT64_MAX        18446744073709551615ULL

/* 7.18.2.2 Limits of minimum-width integer types */
#define INT_LEAST8_MIN    INT8_MIN
#define INT_LEAST16_MIN   INT16_MIN
#define INT_LEAST32_MIN   INT32_MIN
#define INT_LEAST64_MIN   INT64_MIN

#define INT_LEAST8_MAX    INT8_MAX
#define INT_LEAST16_MAX   INT16_MAX
#define INT_LEAST32_MAX   INT32_MAX
#define INT_LEAST64_MAX   INT64_MAX

#define UINT_LEAST8_MAX   UINT8_MAX
#define UINT_LEAST16_MAX  UINT16_MAX
#define UINT_LEAST32_MAX  UINT32_MAX
#define UINT_LEAST64_MAX  UINT64_MAX

/* 7.18.2.3 Limits of fastest minimum-width integer types */
#define INT_FAST8_MIN     INT8_MIN
#define INT_FAST16_MIN    INT16_MIN
#define INT_FAST32_MIN    INT32_MIN
#define INT_FAST64_MIN    INT64_MIN

#define INT_FAST8_MAX     INT8_MAX
#define INT_FAST16_MAX    INT16_MAX
#define INT_FAST32_MAX    INT32_MAX
#define INT_FAST64_MAX    INT64_MAX

#define UINT_FAST8_MAX    UINT8_MAX
#define UINT_FAST16_MAX   UINT16_MAX
#define UINT_FAST32_MAX   UINT32_MAX
#define UINT_FAST64_MAX   UINT64_MAX

/* 7.18.2.4 Limits of integer types capable of holding object pointers */

#if __WORDSIZE == 64
#define INTPTR_MAX        9223372036854775807L
#else
#define INTPTR_MAX        2147483647L
#endif
#define INTPTR_MIN        (-INTPTR_MAX-1)

#if __WORDSIZE == 64
#define UINTPTR_MAX       18446744073709551615UL
#else
#define UINTPTR_MAX       4294967295UL
#endif

/* 7.18.2.5 Limits of greatest-width integer types */
#define INTMAX_MIN        INT64_MIN
#define INTMAX_MAX        INT64_MAX

#define UINTMAX_MAX       UINT64_MAX

/* 7.18.3 "Other" */
#if __WORDSIZE == 64
#define PTRDIFF_MIN	  INT64_MIN
#define PTRDIFF_MAX	  INT64_MAX
#else
#define PTRDIFF_MIN       INT32_MIN
#define PTRDIFF_MAX       INT32_MAX
#endif
//有符号的int型数据取值范围(32位操作系统)
NSLog(@"%d~%d",INT_MIN,INT_MAX);                 // -> -2147483648~2147483647
NSLog(@"%d~%d",INT_LEAST32_MIN,INT_LEAST32_MAX); // -> -2147483648~2147483647


//无符号的32位int型最大值,即2^32-1
NSLog(@"%u",UINT32_MAX);                        // -> 4294967295
NSLog(@"%f",pow(2, 32)-1);                      // -> 4294967295.000000

推荐阅读

C语言数据类型取值范围

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐