Как бы вы определили простой метод "min" в obj-c - PullRequest
21 голосов
/ 24 января 2010

Я хочу определить min и max методы в классе Utils.

@interface Utils

int min(int a, int b);
int max(int a, int b);

@end

Но я не хочу иметь именованные параметры. Это было бы слишком тяжелым обозначением. Я хотел использовать определение в стиле C. Но тогда [Utils min(a, b)] как звонок не работает. В чем моя проблема?

Заранее спасибо за любую помощь

Ответы [ 6 ]

62 голосов
/ 24 января 2010

Это уже определено как макрос.

MIN(a, b)

MAX(a, b)

Вам не нужно переопределять эти.

29 голосов
/ 21 июня 2010

Существует серьезная проблема безопасности с решением, опубликованным Брэндоном Боднаром (которое на момент написания этой статьи было помечено как действительное решение).

Проблема описана здесь: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Min-and-Max.html И (действительное и безопасное) решение для этого: http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Typeof.html

Проверьте сами:

#include <stdio.h>

#define NAIVE_MAX(a,b) (a > b ? a : b)

#define NAIVE_MIN(a,b) (a < b ? a : b)

#if !defined MAX
#define MAX(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a > __b ? __a : __b; })
#endif

#if !defined MIN
#define MIN(a,b) \
({ __typeof__ (a) __a = (a); \
__typeof__ (b) __b = (b); \
__a < __b ? __a : __b; })
#endif

int main (int argc, const char * argv[]) {
    int a = 3;
    int b = 5;

#pragma mark NON-FATAL CASES:
    printf("NAIVE_MAX(%d, %d) => %d\n", a, b, NAIVE_MAX(a, b));
    printf("NAIVE_MIN(%d, %d) => %d\n", a, b, NAIVE_MIN(a, b));

    printf("MAX(%d, %d) => %d\n", a, b, MAX(a, b));
    printf("MIN(%d, %d) => %d\n", a, b, MIN(a, b));

    printf("\nEverything fine so far...\n\n");

#pragma mark FATAL CASES:
    //cache:
    int _a = a;
    int _b = b;
    printf("NAIVE_MAX(%d++, %d++) => %d\n", _a, _b, NAIVE_MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(%d++, %d++) => %d\n", _a, _b, NAIVE_MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MAX(++%d, ++%d) => %d\n", _a, _b, NAIVE_MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("NAIVE_MIN(++%d, ++%d) => %d\n", _a, _b, NAIVE_MIN(++a, ++b));

    printf("\nOuch, this doesn't look right at all!\n\n");

#pragma mark NON-FATAL CASES:
    //reset:
    a = _a;
    b = _b;
    printf("MAX(%d++, %d++) => %d\n", _a, _b, MAX(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(%d++, %d++) => %d\n", _a, _b, MIN(a++, b++));

    //reset:
    a = _a;
    b = _b;
    printf("MAX(++%d, ++%d) => %d\n", _a, _b, MAX(++a, ++b));

    //reset:
    a = _a;
    b = _b;
    printf("MIN(++%d, ++%d) => %d\n", _a, _b, MIN(++a, ++b));

    printf("\nAh, much better now.\n\n");

    return 0;
}

Журнал консоли:

NAIVE_MAX(3, 5) => 5
NAIVE_MIN(3, 5) => 3
MAX(3, 5) => 5
MIN(3, 5) => 3

Everything fine so far...

NAIVE_MAX(3++, 5++) => 6
NAIVE_MIN(3++, 5++) => 4
NAIVE_MAX(++3, ++5) => 7
NAIVE_MIN(++3, ++5) => 5

Ouch, this doesn't look right at all!

MAX(3++, 5++) => 5
MIN(3++, 5++) => 3
MAX(++3, ++5) => 6
MIN(++3, ++5) => 4

Ah, much better now.

Так что никогда не используйте наивную реализацию , как видно из кода выше (и, как предлагает Брэндон Боднар, извините, приятель;)), если вы хотите избежать худших случаев, подобных этим.

18 голосов
/ 24 января 2010

Поскольку вы не используете OS X Реализация target-c, у вас может не быть доступа к предопределенным макросам MIN и MAX.

Вы можете сами определить их как

#define MIN(a,b)    ((a) < (b) ? (a) : (b))
#define MAX(a,b)    ((a) > (b) ? (a) : (b))

Возможно, есть лучший способ определить их, но они создадут простые макросы для вашего использования. Вы можете добавить их в любой общий .h файл, который обычно используют ваши классы.

6 голосов
/ 24 января 2010

Это, вероятно, не очень хорошая идея для данного конкретного приложения, но возможно написать методы Objective C с параметрами «без имен» или, скорее, с именами нулевой длины:

+ min:(int)a :(int)b;
...
[Utils min:a :b]

(Селектор будет @selector(min::).)

1 голос
/ 24 января 2010

Методы класса Objective-C используют именованные параметры, точка. Так оно и есть.

Почему бы не сделать это глобальной бесплатной функцией? Вам не нужен класс Utils для такого рода вещей.

Если вы не хотите загромождать глобальное пространство имен, вы можете использовать Objective-C ++ (переименовать все файлы .m в .mm) и поместить его в пространство имен.

0 голосов
/ 30 июля 2014

В файл шаблона с именем "XXIntegerMath.h" поместите это ...

#import <Foundation/Foundation.h>

static inline NSInteger imax(NSInteger a, NSInteger b) {
    return  a > b ? a : b;
}

static inline NSInteger imin(NSInteger a, NSInteger b) {
    return  a < b ? a : b;
}

Тогда в вашем классе-цели ...

#import "XXIntegerMath.h"
NSInteger minValue = imin(someValue, someOtherValue);

Он не страдает от проблем, описанных Regexident.

...