Xcode 开发,我可以通过一些#define 规则放置#pragma unused(x)

Xcode development, can I place #pragma unused(x) via some #define rule

在 Xcode 中开发时,通常会在 DebugRelease 模式之间切换,并在其中使用部分代码仅调试模式,而在发布模式下不使用某些模式。

我经常根据一些 #define 规则丢弃 NSLog 代码,这些规则让预编译器解析出发布中不需要的那些命令。这样做是因为一些最终测试需要证明一切都按预期工作并且错误仍然得到正确处理而不会弄乱我可能忘记的一些 NSLog。这是在音频开发中很重要的一个例子,在这种情况下,日志记录通常会产生反效果,但在调试时需要。将所有内容包装在 #ifdef DEBUG 中有点麻烦,并且会使代码锁定变得疯狂,因此我的 #defines 可以很好地保持代码简单和可读,而不必担心 NSLog 留在发行版中,同时仍然在需要时故意登录。这种实践对我来说非常有效,可以使用纯发布代码获得适当的测试场景。

但这会导致编译器警告某些变量根本没有被使用。这不是什么大问题,但我想向前迈出一步并尝试摆脱这些警告。现在我可以在 Xcode 中关闭这些警告,但我试图找到一种方法来保留这些警告并只是为了我的 NSLog 否决而摆脱它们 #defines

因此,我没有针对 dev>null 进行记录,而是丢弃(无效化)了 NSLog(... ) 包装的所有代码,并使用了一些额外定义的规则,称为 ALLWAYSLog() 故意将 NSLog 保留在 Releases 中,并将 NSLog 更改为 fprintf 以避免应用程序来源和时间打印。 这是我的规则..

#ifdef DEBUG
 #define NSLog(FORMAT, ...) fprintf(stderr, "%s \n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])
#else
 #define NSLog(FORMAT, ...) {;}
#endif
#define ALLWAYSLog(FORMAT, ...) fprintf(stderr, "%s \n", [[[NSString alloc] initWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])

为了摆脱那些我们经常使用的未使用的变量警告

#pragma unused(variablename)

通知预编译器我们是故意这样做的..

问题:
是否可以编写一些使用 #pragma unused(x)#define 规则?
或者如何集成上述 __unused 属性

的方式

#else的情况下,可以将函数调用放在&&运算符的右侧,左侧为0。这将确保变量被“使用”,同时也确保函数实际上不会被调用并且参数不会被评估。

#ifdef DEBUG
 #define NSLog(FORMAT, ...) fprintf(stderr, "%s \n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String])
#else
 #define NSLog(FORMAT, ...) (0 && fprintf(stderr, "%s \n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]))
#endif

经过测试但仍然不相信没有“官方方式”可以做到这一点,我最终再次阅读了我的头文件。 (usr/include/sys/cdefs.h)

其中 __unused 声明为 __attribute__((__unused__)).

这似乎是通过在代码中的正确位置放置 __unused 指令来告知 Apple Clang (GCC) 编译器不会有意使用特定变量的正式方式。例如在变量声明之前或函数声明之后等.. see Whosebug discussion starting 2013 ongoing

@dbush 的回答过去并且很好,因为它通过使用传递的参数并引入无害的无效逻辑来抑制 未使用的变量警告 - 但会仍然执行找到“未使用的表达式结果”。这非常接近我的目标,可能仍然是最简单的解决方案。

例如:

#define NSLog(...) (0 && fprintf(stderr,"%s",[[NSString alloc] initWithFormat:__VA_ARGS__].UTF8String))

// applied to
int check = 333;
NSLog(@"findMeAgainInPreProcess %d",check);

// preprocesses to
int check = 333;
{0 && fprintf(__stderrp,"%s \n",[[NSString alloc] initWithFormat:@"findMeAgainInPreProcess %d",check].UTF8String);};

虽然这不会打印任何内容,但编译器知道表达式未被使用。

但这让我想知道如何正确完成未使用的标记。尝试一种互惠的方法来区分 Debug 和 Release 以结合我的第一种方法再次使用 __unused...

#define ALLWAYSLog(...) fprintf(stderr,"%s \n",[[NSString alloc] initWithFormat:__VA_ARGS__].UTF8String)
#ifdef DEBUG
#define IN_RELEASE__unused
#define NSLog(...) ALLWAYSLog(__VA_ARGS__)
#else
#define IN_RELEASE__unused __unused
//#define NSLog(...) (0&&ALLWAYSLog(__VA_ARGS__)) //@dbush solution
//#define NSLog(...) NSCAssert(__VA_ARGS__,"")
//#define NSLog(...) {;}
#define NSLog(...) /*__VA_ARGS__*/
#endif

在 Debug 中,它不会通过解析指令本身来消除未使用的变量警告,而在 Release 中,它会根据宏将 IN_RELEASE__unused 转换为 __unused 并将其消除。这是一些额外的工作,但可以帮助查看哪些部分是故意未使用的。

意味着我可以像下面这样输入..

IN_RELEASE__unused int check = 333;
NSLog(@"findMeAgainInPreProcess %d",check);

// produces for DEBUG
int check = 333; //no warning, var is used below
fprintf(__stderrp,"%s \n",[[NSString alloc] initWithFormat:@"findMeAgainInPreCompile %d", check].UTF8String);

// produces for RELEASE
__attribute__((__unused__)) int check = 333; //no warning intentionally
; // no print, nothing

这使 NSLog 保持原样(在代码中),标记未使用的变量以适当地消除警告,并且 NSLog 在 Release 中被完全解析。我仍然可以使用引入的 ALLWAYSLog 为两种模式强制打印。

结论:还是比较直接的