#define太多好吗 ios_ios #define - CSDN
  • iOS-#define详解

    2019-01-29 18:32:20
    底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏(#define)被大量使用,可以说底层开发离开宏(#define)将寸步难行。 不得不说在C系语言(C、Objective-C、C++等)中宏(#define)真是个非常方便又强大的东西...

    前言

    宏(#define)在C系开发中可以说占有举足轻重的作用。底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏(#define)被大量使用,可以说底层开发离开宏(#define)将寸步难行。

    不得不说在C系语言(C、Objective-C、C++等)中宏(#define)真是个非常方便又强大的东西。

    宏(#define)在基本的语法上是非常的简单的,但完全不会影响它的强大。

    不过有时候正因为宏(#define)的简单、方便和强大,就会导致我们平常在使用的时候,其中会有很多的注意点和细节需要我们去注意,如果不小心将其忽略, 那么可能会带来我们意料之外的不想要的结果。

    如果我们要想灵活的使用宏(#define),那么深入了解宏(#define)工作原理和用法必不可少。

    而且经常在iOS开发中使用Objective-C, 那么肯定会经常使用到宏(#define)。

    预编译 

    程序会在预编译之前还会有一些操作, 比如:删除反斜线+换行符的组合, 将各种形式的注释用空格替代等等。

    接着是预编译阶段,预编译在处理#define的时候,会从#开始一直执行到遇到的第一个换行符(写代码的时候换行的作用)为止。

    所以可知#define只会允许定义一行的宏,但是因为预编译之前会删除反斜线+换行符的组合,所以我们可以利用反斜线+换行符来定义多行宏,在将删除反斜线和换行符的组合后,在预编译阶段的逻辑上#define定义就成了一行的宏了。

    #define在预处理阶段只进行文本的替换(相当于把代码拷贝粘贴),不会进行具体的计算。

    #define作用在预编译时期,其真正的效果就是代码替换,而且是直接替换(内联函数!!!),这个和函数有着很大的区别。

    宏(#define)的基本语法:

    #define 宏名 主体;
       ↓   ↓    ↓
    #define PI  3.1415926

    宏(#define)的使用:

    类对象宏:

    类对象宏一般用来定义数据常量或字符串常量。

    #define PI  3.1415926
    
    #define NAME @"SunSatan"

    类函数宏:

    类函数宏就是宏名类似函数名,宏的主体为函数,并可以帮助主体函数接受参数,使用起来就像是函数一样。

    #define Log(x) NSLog(@"this is test: x = %@", x)

    类函数宏和函数的区别是, 类函数宏的参数不指定类型, 具体的参数类型在调用宏的时候由传入的参数决定,这就可能会遇到类型错误的问题。

    举个栗子:

    #define power(x) x*x
    
    int x = 2;
    int pow_1 = power(x);
    int pow_2 = power(x+1);
    
    猜猜pow_1和pow_2的值分别为多少?

    结果是pow_1=4 ,pow_2=5。

    这个结果是不是和预想的不一样,pow_2不应该等于9吗?因为宏真正的效果就是代码替换,所以在预编译后原来的代码变为了:

    #define power(x) x*x
    
    int x = 2;
    int pow_1 = x*x;    //2*2=4
    int pow_2 = x+1*x+1;//2+1*2+1=5
    
    这样看是不是就能看出问题,在代码替换后优先级不对了。
    
    所以想要得到正确的结果的宏定义如下:
    
    #define power(x) (x)*(x)

    这个栗子就是告诉大家定义类函数宏的时候就真的要小心,不然得到结果可能会出乎我们的意料。

    宏(#define)中操作符的使用:

    #:字符串化操作符,需要放置在参数前,将类函数宏中传入的参数用""括起来变成了c语言的字符串。

    #define Log(x) #x
    
    代码替换后:
    Log(x) -> "x"
    
    所以以下两种使用方法都没问题,打印信息都是 x
    NSLog(@"%s", Log(x)); -> NSLog(@"%s", "x");
    NSLog(@"%@",@Log(x)); -> NSLog(@"%@",@"x");

    ##:符号连接操作符,需要放置在参数前,参数就会和##前面的符号连接起来。

    #define single(name) +(instancetype)share##name;
    
    代码替换后:
    single(SunSatan) -> +(instancetype)shareSunSatan;

    宏(#define)的好处:

    使用宏的好处是不言自明的,可以少写很多重复的代码,修改一处就可以完成全局修改,在节省工作量的同时,大大增加代码可读性。

    如果想成为一个能写出漂亮优雅代码的开发者,宏绝对是必不可少的技能。

    使用宏(#define)的建议:

    多多使用类函数宏对开发者而言是非常灵活、方便的,可以抽离很多重复使用的冗长的代码段,增加代码可读性,节省工作量。

    使用但不是滥用,应有节制。

    使用大量的宏,每次修改宏都需要重新替换,导致编译时间久。

    不建议使用类对象宏,因为类对象宏定义的是常量,既然都要定义为常量,那么我们应该使用const来修饰。

    相对于定义常量而言,const要比宏效率高很多,而且宏不做检查,只是代码替换,而const会进行编译检查,const要比宏更安全。所以应尽可能的使用const来代替类对象宏。

    展开全文
  • 以下内容只是抛砖引玉,希望大家提意见,改错误,简单的宏使用方法就不做解释了,来点扩展的

    以下内容只是抛砖引玉,希望大家多提意见,多改错误,太简单的宏使用方法就不做解释了,来点扩展的

    //没用#define前是这样的,每个ViewController都要写这么一段重复的代码 写多了就烦了

        /***********************处理前*****************************/

        UILabel *titleLabel = [[UILabel allocinit];

        titleLabel.backgroundColor  = [UIColor clearColor];

        titleLabel.textColor        = [UIColor redColor];

        titleLabel.text             = @"导航栏标题";

        titleLabel.font=[UIFont fontWithName:nil size:17.0f];

        [titleLabel sizeToFit];

        self.navigationItem.titleView = titleLabel;


    //在全局配置文件(config.h)中定义了一个宏

    #define SET_NAV_TITLE(_TITLE) ({\

    UILabel *titleLabel = [[UILabel alloc] init];\

    titleLabel.backgroundColor  = [UIColor clearColor];\

    titleLabel.textColor        = [UIColor redColor];\

    titleLabel.text             = _TITLE;\

    titleLabel.font=[UIFont fontWithName:nil size:17.0f];\

    [titleLabel sizeToFit];\

    self.navigationItem.titleView = titleLabel;\

    })


        //定义了宏后就这么一句了

        /***********************处理后*****************************/

        SET_NAV_TITLE(@"导航栏标题");

        

        //向大家请教个问题,怎么向宏里面传一个实例对象进去,可不可以实现


    最后给大家介绍一个好玩的,试调时很好用,把下面一段代码复制到.pch中,你打印的时候就能看到效果了


    //一个很高级的 NSLog

    #define NSLog(format, ...) do {      \

    fprintf(stderr, "<%s : %d> %s\n",                                           \

    [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \

    __LINE__, __func__);                                                        \

    (NSLog)((format), ##__VA_ARGS__);                                           \

    fprintf(stderr, "-------------------------------完美分割线---嘿嘿----------------------------\n");          \

    } while (0)


    展开全文
  • iOS开发中请尽量使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速度。 宏定义大家应该都不陌生,使用起来非常简单,首先我们先来看一下宏定义跟const...

    在iOS开发中请尽量多使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速度。

    • 宏定义大家应该都不陌生,使用起来非常简单,首先我们先来看一下宏定义跟const的区别:

    1.宏在编译开始之前就会被替换,而const只是变量进行修饰;

    2.宏可以定义一些函数方法,const不能

    3.宏编译时只替换不做检查不报错,也就是说有重复定义问题。而const会编译检查,会报错

    • 那到底什么时候使用宏,什么时候该使用const?

    定义全局变量的时候,我们应该尽量先考虑使用 static 方式声名const来替代使用宏定义。const不能满足的情况再考虑使用宏定义。比如用以下定义:

    1
    2
    static NSString * const CLASSNAMEconst = @"Hello"
    static const CGFloat CLASSNAMEWidth = 10.0;

    代替:

    1
    2
    #define CLASSNAMEDEFINE @"Hello"
    #define CLASSNAMEWIDTH 10.0

    对于整型类型,代替宏定义直接定义整型常量比较好的办法是使用enum,使用enum时推荐使用NS_ENUM和NS_OPTIONS宏。比如用以下定义:

    1
    2
    3
    typedef NS_ENUM(NSInteger,TestEnum) {
          MY_INT_CONST = 12345
    };

    代替:

    1
    #define MY_INT_CONST 12345

    NS_OPTIONS定义方式如下:

    1
    2
    3
    4
    5
    6
    typedef NS_OPTIONS(NSInteger, SelectType) {
          SelectA    = 0,
          SelectB    = 1 << 0,
          SelectC    = 1 << 1,
          SelectD    = 1 << 2
    };

    下面顺便说一下const 的一些使用方式,主要说明这几种写法的区别:

    1
    2
    3
    4
    5
    const NSString *constString1 = @"I am a const NSString * string";
    NSString const *constString2 = @"I am a NSString const * string";
    static const NSString *staticConstString1 = @"I am a static const NSString * string";
    static NSString const *staticConstString2 = @"I am a static NSString const * string";
    NSString * const stringConst = @"I am a NSString * const string";

    全局变量:

    1
    2
    3
    4
    5
    6
    //全局变量,constString1地址不能修改,constString1值能修改
    const NSString *constString1 = @"I am a const NSString * string";
    //意义同上,无区别
    NSString const *constString2 = @"I am a NSString const * string";
    // stringConst 地址能修改,stringConst值不能修改
    NSString * const stringConst = @"I am a NSString * const string";

    constString1 跟constString2 无区别,外部使用要配合extern字段如:

    1457495-ca65539a537695e4.jpg

    在ViewController.m中定义全局变量在TestViewController.m中使用需要使用

    1
    2
    extern NSString *constString1;
    NSLog(@"constString1:%@\n",constString1);

    局部常量:

    1
    2
    3
    4
    //作用域只在本文件中,在其他类中使用需引用定义的类
    static const NSString *staticConstString1 = @"I am a static const NSString * string";
    static NSString const *staticConstString2 = @"I am a static NSString const * string";
    展开全文
  • iOS开发中请尽量使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速度。 宏定义大家应该都不陌生,使用起来非常简单,首先我们先来看一下宏定义跟const...

    在iOS开发中请尽量多使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速度。

    • 宏定义大家应该都不陌生,使用起来非常简单,首先我们先来看一下宏定义跟const的区别:

    1.宏在编译开始之前就会被替换,而const只是变量进行修饰;

    2.宏可以定义一些函数方法,const不能

    3.宏编译时只替换不做检查不报错,也就是说有重复定义问题。而const会编译检查,会报错

    • 那到底什么时候使用宏,什么时候该使用const?

    定义全局变量的时候,我们应该尽量先考虑使用 static 方式声名const来替代使用宏定义。const不能满足的情况再考虑使用宏定义。比如用以下定义:

    1
    2
    static NSString * const CLASSNAMEconst = @"Hello"
    static const CGFloat CLASSNAMEWidth = 10.0;

    代替:

    1
    2
    #define CLASSNAMEDEFINE @"Hello"
    #define CLASSNAMEWIDTH 10.0

    对于整型类型,代替宏定义直接定义整型常量比较好的办法是使用enum,使用enum时推荐使用NS_ENUM和NS_OPTIONS宏。比如用以下定义:

    1
    2
    3
    typedef NS_ENUM(NSInteger,TestEnum) {
          MY_INT_CONST = 12345
    };

    代替:

    1
    #define MY_INT_CONST 12345

    NS_OPTIONS定义方式如下:

    1
    2
    3
    4
    5
    6
    typedef NS_OPTIONS(NSInteger, SelectType) {
          SelectA    = 0,
          SelectB    = 1 << 0,
          SelectC    = 1 << 1,
          SelectD    = 1 << 2
    };

    下面顺便说一下const 的一些使用方式,主要说明这几种写法的区别:

    1
    2
    3
    4
    5
    const NSString *constString1 = @"I am a const NSString * string";
    NSString const *constString2 = @"I am a NSString const * string";
    static const NSString *staticConstString1 = @"I am a static const NSString * string";
    static NSString const *staticConstString2 = @"I am a static NSString const * string";
    NSString * const stringConst = @"I am a NSString * const string";

    全局变量:

    1
    2
    3
    4
    5
    6
    //全局变量,constString1地址不能修改,constString1值能修改
    const NSString *constString1 = @"I am a const NSString * string";
    //意义同上,无区别
    NSString const *constString2 = @"I am a NSString const * string";
    // stringConst 地址能修改,stringConst值不能修改
    NSString * const stringConst = @"I am a NSString * const string";

    constString1 跟constString2 无区别,外部使用要配合extern字段如:

    1457495-ca65539a537695e4.jpg

    在ViewController.m中定义全局变量在TestViewController.m中使用需要使用

    1
    2
    extern NSString *constString1;
    NSLog(@"constString1:%@\n",constString1);

    局部常量:

    1
    2
    3
    4
    //作用域只在本文件中,在其他类中使用需引用定义的类
    static const NSString *staticConstString1 = @"I am a static const NSString * string";
    static NSString const *staticConstString2 = @"I am a static NSString const * string";
    展开全文
  • #if !defined()#define

    2014-10-08 21:40:59
    #if !defined()#define

    为了避免同一个文件被include多次

    1  #ifndef方式
    2  #pragma once方式

    在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
        方式一:

        #ifndef __SOMEFILE_H__
        #define __SOMEFILE_H__
        ... ... // 一些声明语句
        #endif

        方式二:

        #pragma once
        ... ... // 一些声明语句


        #ifndef的方式
    依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

        #pragma once则由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。

      方式一由语言支持所以移植性好,方式二 可以避免名字冲突。

    一般可以这样处理:
    #infndef XX
    #define XX
        #if _MSC_VER > 1000
            #pragma once
        #endif
        .
        .
    #endif
    注意:  _MSC_VER 是出于版本兼容性考虑,定义
                    Defines the compiler version. Defined as 1200 for Microsoft Visual C++ 6.0. Always defined.

    转载:http://blog.sina.com.cn/s/blog_5da90bfc0100cpix.html

    展开全文
  • 提及#define,你会不会马上联想到自己时时用#define MAX 100用于标记一个数组的长度?这样做无非两个原因,一来,#define是编译时的宏展开,对运行时间毫无影响。其二,使用诸如MAX这类见名知其意的标识符代替生硬的...
  • #define vs const in Objective-C 问题: 我是一个 Objective-C 的新手。我有几个关于 const 和 预处理指令 #define 的问题。 第一,我发现不能用 #define 定义一个常量类型,为什么会这样? 第二,它们...
  • Q : 在项目的 .h 文件中, #ifndef XXX_h #define XXX_h //程序段1 #endif /* XXX_h */ 的作用? Q : #if , #ifdef , #ifndef 的使用方法?
  • iOS 7:漫谈#define 宏定义 #define宏定义在C系开发中可以说占有举足轻重的作用。底层框架自不必说,为了编译优化和方便,以及跨平台能力,宏被大量使用,可以说底层开发离开define将寸步难行。而在更高层级进行...
  • 重要的事情首先说:在iOS开发中请尽量使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速度。 宏定义大家应该都不陌生,使用起来非常简单,首先我们先来...
  • 重要的事情首先说: 在iOS开发中请尽量使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的运行速度(这点待考证) 宏定义大家应该都不陌生,使用起来非常简单,首先...
  • http://www.cocoachina.com/ios/20160530/16483.html ...重要的事情首先说:在iOS开发中请尽量使用const、enum来代替宏定义(#define);随着项目工程的逐渐增大,过多的宏定义还可能影响项目的编译速...
  • iOS学习:iOS代码规范

    2016-05-03 19:55:46
    iOS代码规范 Import规范 Define规范 Paragma Mark 规范 Interface规范 implementation规范 实例规范 NSDictionary规范 NSArray规范 函数规范 If-Else规范 For-In For 规范 Block规范 运算符规范 命名规范 实例命名...
1 2 3 4 5 ... 20
收藏数 11,498
精华内容 4,599
关键字:

#define太多好吗 ios