美文网首页
预处理(宏)——想说爱你不容易

预处理(宏)——想说爱你不容易

作者: 行知路 | 来源:发表于2022-05-19 15:45 被阅读0次

一、工作中遇到的怪事

在编写代码是,发现了一个崩溃:

// XXXX.m

#if MOU_GE_HONG_DING_YI == 1
        _library = // 涉密,删除代码;从路径A获取文件
#else
        // 崩溃发生在这里
        _library = // 涉密,删除代码;从路径B获取文件
#endif

但是没有改动到这里,却发生了崩溃!

  1. 经分析,初步判断可能是需要走if分支,但是却走到了else分支
  2. 发现在路径A确实存在文件、而路径B却不存在这个文件
  3. 那么问题就发生在编译XXXX.m文件时,宏MOU_GE_HONG_DING_YI尚未被定义

二、问题详解

2.1 代码展示

// 宏在此文件中定义
// Header.h

#define MOU_GE_HONG_DING_YI 1
// 宏在此文件中使用
//  XXXX.m

#if MOU_GE_HONG_DING_YI == 1
        _library = // 涉密,删除代码;从路径A获取文件
#else
        // 崩溃发生在这里
        _library = // 涉密,删除代码;从路径B获取文件
#endif

2.2 大胆猜测

根据问题表现,猜测是编译器在预处理XXXX.m文件时,其尚未了解到有MOU_GE_HONG_DING_YI的宏定义,所以就把if分支的代码去掉了,只保留了else分支的代码。

2.3 小心求证

2.3.1 复现问题

为了验证自己的猜测,编写如下测试代码;

// Person.h
@interface Person : NSObject
+ (void)testMacro;
@end




// Person.m
@implementation Person

// DEBUG 是Xcode预置的
// THIS_IS_A_TEST_MACRO 在Person的子类Student类中声明

+ (void)testMacro {
#ifdef DEBUG
    NSLog(@"Person Define DEBUG");
#else
    NSLog(@"Person NO Define DEBUG");
#endif
    
#if THIS_IS_A_TEST_MACRO == 1
    NSLog(@"Person Define THIS_IS_A_TEST_MACRO");
#else
    NSLog(@"Person NO THIS_IS_A_TEST_MACRO");
#endif
}

@end





// Student.h
#define THIS_IS_A_TEST_MACRO 1

@interface Student : Person

+ (void)StudentTestMacro;

@end




// Student.m
@implementation Student

+ (void)StudentTestMacro {
#ifdef DEBUG
    NSLog(@"Student Define DEBUG");
#else
    NSLog(@"Student NO Define DEBUG");
#endif
    
#if THIS_IS_A_TEST_MACRO == 1
    NSLog(@"Student Define THIS_IS_A_TEST_MACRO");
#else
    NSLog(@"Student NO THIS_IS_A_TEST_MACRO");
#endif
    
    [super testMacro];
}
@end



// main.m
int main(int argc, const char * argv[]) {
    [Student StudentTestMacro];
    return 0;
}

/*
2022-05-19 14:51:49.164576+0800 cmdProject[75822:301165] Student Define DEBUG
2022-05-19 14:51:49.165422+0800 cmdProject[75822:301165] Student Define THIS_IS_A_TEST_MACRO
2022-05-19 14:51:49.165453+0800 cmdProject[75822:301165] Person Define DEBUG
2022-05-19 14:51:49.165474+0800 cmdProject[75822:301165] Person NO THIS_IS_A_TEST_MACRO
*/
  1. 由于Student继承自Person,所以编译器优先处理Person的相关代码
  2. 在对Person进行预处理的时候,尚未了解到THIS_IS_A_TEST_MACRO宏已被定义,所以至保留了else分支

通过代码验证了之前的猜测——某些预处理与文件的依赖有关系,如果宏定义在子孙文件里,则父文件的预处理会出乎预料

2.2.2 代码实证

2.2.2.1 XXXX.m原代码预处理

// XXXX.i

    // 可见在原始代码中,由于引入了Header.h,所有走了if分支
    # 1 "...../common/Header.h" 1

     _library = // 涉密,删除代码;从路径A获取文件

2.2.2.2 修改XXXX.m后代码预处理

// XXXX.i

    // 可见在原始代码中,由于引入了Header.h,所有走了else分支
     _library = // 涉密,删除代码;从路径B获取文件

三、最佳实现

3.1 不推荐使用宏

绝大部分的程序员都听说过,不要使用宏。它有许多问题:

  1. 丢失类型
  2. 可能包含隐蔽错误(如加的小括号过少)
  3. 不支持调试
  4. 在预处理阶段被处理掉,重要信息丢失(语法、语义等后续阶段的编译处理无法获取宏信息)
  5. .......
    宏的不好,不一而足,以上仅列举部分

3.2 不得不使用宏

宏就像“渣男、渣女”一样,除了渣,别的地方都很好!


渣男

扯远啦!
宏虽然有万般不好,但是许多地方仍然被使用!除了其他的一些宏编写的最佳时间外,推荐大家在XCode的工程配置里定义宏(除非你非常确定宏的应用范围在且只在当前文件范围内),这样就可以规避此问题。

相关文章

  • 预处理(宏)——想说爱你不容易

    一、工作中遇到的怪事 在编写代码是,发现了一个崩溃: 但是没有改动到这里,却发生了崩溃! 经分析,初步判断可能是需...

  • 想说爱你不容易

    想说爱你不容易 想说爱你不容易 想说爱你不容易 ………………… 想说爱你不容易,我的父亲母亲! 你们每天拼命地挣钱...

  • 2017-05-22

    跑步,想说爱你不容易

  • C语言预处理指令

    预处理指令 宏定义 宏定义会在预处理的时候, 用宏定义的值来替换宏的名称 格式: #define 宏名称 宏值 应...

  • 想说读书不容易

    记得有句歌词叫"想说爱你不容易",可是在如今看来,想说爱你很容易,张口就来。要我说,想说读书不容易,撇开手机...

  • 10/19

    今天老师讲了预处理命令,宏定义分为无参宏定义,带参宏定义和条件编译。宏定义包括宏名和宏展开,和函数相比预处理有很多...

  • 2020,真不容易

    二零二零,爱你爱你,多美的字眼。我想说,爱你不容易,真不容易。2020年如今已成为历史,诸多的不容易,让人久久难以...

  • 想说“爱你”不容易

    一、成功无捷径——来自学生的打击 在我看来,来自学生的各种打击是家常便饭,不断向我袭来。因此执教鞭的我就像舞...

  • “性教育”想说爱你不容易:由9岁女童做人流所思? (中)

    “性教育”想说爱你不容易:由9岁女童做人流所思? (中) (注 《“性教育”想说爱你不容易:由9岁女童做人流所思?...

  • “性教育”想说爱你不容易:由9岁女童做人流所思? (下)

    “性教育”想说爱你不容易:由9岁女童做人流所思? (下) (注 《“性教育”想说爱你不容易:由9岁女童做人流所思?...

网友评论

      本文标题:预处理(宏)——想说爱你不容易

      本文链接:https://www.haomeiwen.com/subject/bbutprtx.html