iOS实践

iOS C、C++知识补漏

2021-10-22  本文已影响0人  山杨

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

#include <stdio.h>
#include <string.h>
 
union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main( ) {
   union Data data; 
   printf( "数据大小: %d\n", sizeof(data));
   return 0;
}
结果输入是20
共用体占用的内存应足够存储共用体中最大的成员,也就是char str[20]。
  1. 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
  2. 所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
  3. 位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;
data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。
#include <stdio.h>
#include <string.h>
 
struct
{
  unsigned int age : 3;
} Age;
 
int main( )
{
   Age.age = 4;
   printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
   printf( "Age.age : %d\n", Age.age );
 
   Age.age = 8; // 二进制表示为 1000 有四位,超出
   printf( "Age.age : %d\n", Age.age );
 
   return 0;
}
结果:
Sizeof( Age ) : 4
Age.age : 4
Age.age : 0
int main(){
    struct bs{
        unsigned a:1;
        unsigned b:3;
        unsigned c:4;
    } bit,*pbit;
    bit.a=1;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    bit.b=7;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    bit.c=15;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    printf("%d,%d,%d\n",bit.a,bit.b,bit.c);    /* 以整型量格式输出三个域的内容 */
    pbit=&bit;    /* 把位域变量 bit 的地址送给指针变量 pbit */
    pbit->a=0;    /* 用指针方式给位域 a 重新赋值,赋为 0 */
    pbit->b&=3;    /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */
    pbit->c|=1;    /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */
    printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);    /* 用指针方式输出了这三个域的值 */
}
  1. 位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k{
    int a:1;
    int  :2;    /* 该 2 位不能使用 */
    int b:3;
    int c:2;
};

案例1

在YSObject.m文件中设置MyKey的值,这种没有任何限制的情况下默认是全局变量,看似没有暴露在YSObject.h文件中的全局变量却有被外部访问的风险。

NSString *MyKey = @"testKey";
@implementation YSObject
@end

在ViewController.m的文件中添加MyKey的声明extern NSString *MyKey;

extern NSString *MyKey;
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  NSLog(@"MyKey = %@", MyKey);
}
@end

成功打印结果: MyKey = testKey

  • 声明为局域变量:用static限制
    static NSString *MyKey = @"testKey";
    
  • 声明为局域常量:用staticconst限制
    static NSString * const MyKey = @"testKey";
    
  • 使用static声明的变量/常量,也可以暴露在YSObject.h文件中,外部导入该文件后,就可以直接访问到MyKey的值。但外部访问的MyKey是深拷贝出来的,因为内存地址和原来YSObject.h中的不同,所以在外部修改后对原文件(YSObject.h)内部的MyKey值没有影响。

案例2

在YSObject.h文件中声明MyKey的值

extern NSString *MyKey;
@interface YSObject : NSObject
@end

在YSObject.m文件中设置MyKey的值

NSString *MyKey = @"testKey";
@implementation YSObject 
@end

从外部引入YSObject.h文件后可以访问并且修改MyKey的值,并且因为是全局变量,只要修改MyKey的值就会对全局产生影响,是非线程安全的。

  • 如果MyKey需要被声明为一个全局常量,最好使用const限制为不能修改,否则安全性也会降低
    extern NSString * const MyKey;
    
struct __main_block_impl_0 {
  NSString **name;
  int age;
  NSString *address;
  __main_block_impl_0(NSString **_name, int _age, NSString *_address) : name(_name), age(_age), address(_address) {
    
  }
};
等价于
struct __main_block_impl_0 {
  NSString **name;
  int age;
  NSString *address;
  __main_block_impl_0(NSString **_name, int _age, NSString *_address) {
    name = _name;
    age = _age;
    address = _address;
  }
};
image.png
int a = 1;
等价于
auto int a = 1;
自动变量,离开作用域就销毁
上一篇下一篇

猜你喜欢

热点阅读