Managing Functions and Function Pointers

Panther·2021년 8월 14일
0

https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/managing_functions_and_function_pointers

"Ensure that your code correctly handles functions, function pointers, and Objective-C messages."

코드가 정확하게 함수, 함수 포인터, Objective-C 메시지를 처리할 수 있도록 보장합니다.

Overview

64비트 런타임은 함수 호출 및 처리에서 몇 가지 변경점을 갖습니다. 이러한 변경점들은 함수가 여러 인수를 어떻게 수용하는지, Objective-C 메시지가 코드에서 어떻게 호출되는지에 영향을 미칩니다. 아래에 규정된 컨벤션을 채택하고 호출함으로써 코드가 이러한 변경점에 따를 수 있도록 만드시기 바랍니다.

Always Define Function Prototypes

업데이트된 프로젝트 설정을 사용해 컴파일할 때, 명시적 프로토타입을 갖지 않는 함수에 함수 호출을 시도하는 경우 컴파일러는 에러를 생성합니다. 컴파일러가 가변적인 함수인지 아닌지 확인할 수 있도록 함수 프로토타입을 제공해야 합니다.

Ensure that Function Pointers Use the Correct Prototype

코드에서 함수 포인터를 전달하면, 호출 컨벤션은 모든 곳에서 코드에 있는 같은 파라미터 집합을 가져와야 합니다. 가변적인 함수를 파라미타 수가 고정된 함수에 캐스팅하지 않아야 하며, 반대의 경우도 캐스팅하지 않아야 합니다.

아래 코드는 문제를 발생하는 함수 호출의 예시를 보여줍니다.

int MyFunction(int a, int b, ...);

int (*action)(int, int, int) = (int (*)(int, int, int)) MyFunction;
action(1,2,3); // Incorrect.

이 예시의 함수 포인터가 다른 호출 컨벤션 집합을 사용하기 위해 캐스팅되기 때문에 호출 함수는 호출되는 함수가 기대하지 않은 순서로 파라미터를 위치시킵니다. 이와 같은 동작은 앱이 충돌하거나 예측하지 못하는 동작을 보여줄 것입니다.

Call Variadic Functions with Consistent Types

가변 함수는 변수 인수 리스트(varargs)를 포함하는 함수입니다. 함수 인수는 타입 정보를 제공하지 않습니다. 게다가 자동으로 가변 함수의 인수는 더 큰 타입으로 승격되지 않습니다. 64비트 런타임에서 가변 함수에 다른 크기의 타입을 전달하는 경우 이러한 동작을 이해하는 것은 중요합니다.

들어오는 다른 데이터 타입들 사이를 구분할 필요가 있다면, 포맷 스트링 혹은 varargs 함수에 해당 정보를 제공하는 유사한 메커니즘의 무엇을 사용하시기 바랍니다. 만약 호출 함수가 정확한 정보를 제공하지 않는다면(혹은 만약 varargs 함수가 정확하게 해석할 수 없다면), 부정확한 결과를 가져오게 될 것입니다.

예를 들어 만약 varargs 함수가 긴 인티저를 요구하고 32비트 값을 전달하면, 함수는 전달받은 32비트 데이터 및 다음 인수로부터의 32비트 데이터를 포함하게 됩니다. 유사하게 varargs 함수가 int 타입을 요구하고 여기에 긴 인티저를 전달하면, 절반의 데이터만을 가져옵니다. 전달한 데이터의 남은 32비트 데이터는 따라오는 인수에서 나타납니다.

Cast Objective-C Messages in Proper Form

코드가 objc_msgSend 함수 혹은 Objective-C 런타임에서 메시지를 보내는 기타 유사한 함수를 호출하면, 이에 적합하게 캐스팅할 필요가 있습니다. 메시지 함수에 대한 프로토타입이 가변적인 형태일지라도 Objective-C 런타임에서 호출되는 메소드 함수는 같은 프로토타입을 공유하지 않습니다.

Objective-C 런타임은 메소드를 구현한 함수를 직접 호출합니다. 그렇기 때문에 호출 컨벤션은 일치하지 않게 됩니다. 호출되는 메소드 함수와 일치하는 프로토타입에 objc_msgSend 함수를 캐스팅해야 합니다.

아래 코드는 객체에 메시지를 디스패치하기 위한 적합한 형태를 보여주고 있습니다. 저수준 메시지 함수를 사용하고 있습니다.

- (int) doSomething:(int) x {
   return x + 2;
}

- (void) doSomethingElse {
    int (*action)(id, SEL, int) = (int (*)(id, SEL, int)) objc_msgSend;
    action(self, @selector(doSomething:), 0);
}

이 예시에서 doSomething: 메소드는 단일 파라미터 x를 받으며, 가변 형태를 갖지 않습니다. doSomethingElse에서 메소드 함수의 프로토타입을 사용하면서 objc_msgSend 함수를 캐스팅하고 있습니다. 메소드 함수는 항상 처음 두 파라미터로 id 변수와 셀렉터를 받는다는 것을 기억하시기 바랍니다. objc_msgSend 함수가 함수 포인터 네임드 액션에 캐스팅된 후 해당하는 같은 함수 포인터를 통해 호출이 디스패치됩니다.

See Also


Memory and Pointer Access

Updating Data Structures

앱의 데이터 디자인을 리뷰하고 64비트 아키텍처를 따르도록 업데이트합니다.

https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/updating_data_structures
https://velog.io/@panther222128/Updating-Data-Structures

Auditing Pointer Usage

코드에 있는 포인터가 64비트 런타임에서 안전하도록 보장합니다.

https://developer.apple.com/documentation/uikit/app_and_environment/updating_your_app_from_32-bit_to_64-bit_architecture/auditing_pointer_usage
https://velog.io/@panther222128/Auditing-Pointer-Usage


0개의 댓글