gpt4 book ai didi

ios - Objective-C: "format string is not a string literal (potentially insecure)"宏警告

转载 作者:可可西里 更新时间:2023-11-01 04:22:35 28 4
gpt4 key购买 nike

我正在使用宏来简化返回本地化字符串的过程,如下所示:

#define GetLocalStr(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]

基本上,如果您在本地化字符串文件中有一个条目,例如 "name"= "My name is %@";,调用

GetLocalStr( @"name", @"Foo" );

将返回 NSString @"My name is Foo"

但是,当我运行它时,例如:

NSString * str = GetLocalStr( @"name", @"Foo" );

我收到“格式字符串不是字符串文字”警告。即使遵循关于此警告的其他答案的建议,并将其替换为:

NSString * str = [NSString stringWithFormat:@"%@", GetLocalStr( @"name", @"Foo" )];

我仍然收到警告,此外,它有点违背了宏让生活更轻松的意义。

如何在 #pragma suppressors 中去掉所有 GetLocalStr 调用的警告?

编辑 27/08

在浏览了 CRD 的答案并做了更多测试之后,我似乎对错误做出了错误的假设。澄清一下:

本地化字符串文件:

"TestNoArgs" = "Hello world";
"TestArgs" = "Hello world %@";

代码:

NSString * str1 = GetLocalStr( @"TestNoArgs" ); // gives warning
NSString * str2 = GetLocalStr( @"TestArgs", @"Foo" ); // doesn't give warning

我的大部分翻译都没有论据,那些是发出警告的,但在阅读 CRD 的回答之前我没有建立联系。

我将我的单个宏更改为两个,如下所示:

#define GetLocalStrNoArgs(key) \
[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil]

#define GetLocalStrArgs(key, ...) \
[NSString stringWithFormat:[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil], ##__VA_ARGS__]

如果我分别调用每一个,则不会有任何警告。

我希望 GetLocalStr 扩展为 GetLocalStrNoArgsGetLocalStrArgs 取决于是否传递了任何参数,但到目前为止我一直没有运气(宏不是我的强项 :D)。

我正在使用 sizeof(#__VA_ARGS__) 来确定是否传递了任何参数 - 它对参数进行字符串化,如果大小为 1,则为空(即“\0”)。也许这不是最理想的方法,但它似乎有效。

如果我将 GetLocalStr 宏重写为:

#define GetLocalStr(key,...) (sizeof(#__VA_ARGS__) == 1) ? GetLocalStrNoArgs(key) : GetLocalStrArgs(key,##__VA_ARGS__)

我可以使用它,但我仍然会在使用它的任何地方收到警告并且没有传递任何参数,而像

#define GetLocalStr( key,...)               \
#if ( sizeof(#__VA_ARGS__) == 1 ) \
GetLocalStrNoArgs(key) \
#else \
GetLocalStrArgs(key,##__VA_ARGS__)

不会编译。如何让我的 GetLocalStr 宏正确扩展?

最佳答案

Clang 和 GCC 编译器会检查格式字符串和提供的参数是否一致,如果格式字符串不是文字,它们将无法执行此操作 - 因此您在从包中获取格式字符串时会看到错误消息。

为了解决这个问题,有一个属性 format_arg(n) ( docs ),用于标记采用格式字符串的函数;以某种方式改变它而不改变实际的格式说明符,例如翻译它;然后返回它。 Cocoa 为该属性提供了方便的宏NS_FORMAT_ARG(n)

要解决您的问题,您需要做两件事:

  1. 在指定了此属性的函数中结束对 NSBundle 的调用;和

  2. 更改您的“ key ”以包含格式说明符。

其次,您的字符串文件应包含:

"name %@" = "My name is %@"

因此键具有与结果相同的格式说明符(如果您需要为特定语言重新排序说明符,您可以使用位置格式说明符)。

现在定义一个简单的函数来进行查找,将其归因于格式转换函数。请注意,我们将其标记为 static inline,使用宏 NS_INLINE 作为编译器将其内联到您的宏扩展中的提示; static 允许您将它包含在多个文件中而不会出现符号冲突:

NS_INLINE NSString *localize(NSString *string) NS_FORMAT_ARGUMENT(1);
NSString *localize(NSString *string)
{
return [[NSBundle mainBundle] localizedStringForKey:string value:@"" table:nil];
}

你的宏变成:

#define GetLocalStr(key, ...) [NSString stringWithFormat:localize(key), ##__VA_ARGS__]

现在当你:

GetLocalStr(@"name %@", @"Foo")

您将获得本地化的格式字符串和格式检查。

更新

在 Greg 发表评论后,我回去检查了 - 我重现了您的错误,因此假设这是由于缺少属性。然而,正如 Greg 指出的那样 localizedStringForKey:value:table: 已经有了属性,那么为什么会出现错误呢?我在重现您的错误时心不在焉地做了什么:

NSLog( GetLocalStr( @"name %@", @"Foo" ) );

并且编译器指向定义而不是那一行——我应该发现编译器误导了我。

那么,这会给您带来什么影响呢?也许你做过类似的事情?关键是格式字符串必须是文字或归因于格式转换函数的函数/方法的结果。别忘了,您还必须具有上述 key 的格式说明符。

更新 2

在您添加注释之后,您需要使用的是函数,而不是宏,以及 format 属性,Cocoa 为此提供了方便的 NS_FORMAT_FUNCTION(f,a) 宏。此属性通知编译器该函数是格式化函数,f 的值是格式字符串的编号,a 是格式的第一个参数的编号.这给出了函数声明:

NSString *GetLocalStr(NSString *key, ...) NS_FORMAT_FUNCTION(1,2);

和定义(假设 ARC):

NSString *GetLocalStr(NSString *key, ...)
{
va_list args;
va_start(args, key);
NSString *format = [[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil];
NSString *result = [[NSString alloc] initWithFormat:format arguments:args];
va_end (args);
return result;
}

(与@A-Live 的基本相同)。

这个的使用将被适本地检查,例如:

int x;
...
NSString *s1 = GetLocalStr(@"name = %d", x); // OK
NSString *s2 = GetLocalStr(@"name = %d"); // compile warning - More '%" conversions than data arguments
NSString *s3 = GetLocalStr(@"name", x); // compile warning - Data argument not used by format string
NSString *s4 = GetLocalStr(@"name"); // OK

关于ios - Objective-C: "format string is not a string literal (potentially insecure)"宏警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18449176/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com