2016-11-29 1 views
1

Swift에서 다음 C 코드를 작성하는 방법은 무엇입니까? TrueType 'cmap'을 읽는 중 형식 4 Swift에서 서브 테이블 3

glyphIndex = *(&idRangeOffset[i] + idRangeOffset[i]/2 + (c - startCode[i])) 

나는 간단한 작은 이진 데이터 판독기를 사용하여 포맷 4 트루 타입 문자 매핑 테이블을 읽으려고 해요. C에서 작업 할 때 포인터의 머리 또는 꼬리를 간신히 할 수 있기 때문에 포인터 조작이 포함될 때까지는 모두 훌륭하고 좋은 것입니다. 접두어가 붙어있는 Unsafe 접두사로 가두는 것만은 말할 것도없고.

여러 가지를 시도했지만 아무 것도 제대로 작동하지 않는 것 같습니다. 나는 Swift에서 포인터 "주소"를 사용하는 방법을 정확히 모르겠다. 당신이 ???을 알 수 위의 코드에서

// The following variables are all [UInt16]: 
// - startCodes 
// - endCodes 
// - idDeltas 
// - idRangeOffsets 

var gids = [Int]() 

// Iterate segments, skipping the last character code (0xFFFF) 
for i in 0 ..< segCount - 1 { 

    let start = startCodes[i] 
    let end = endCodes[i] 
    let delta = idDeltas[i] 
    let rangeOffset = idRangeOffsets[i] 
    let charRange = start ..< (end + 1) 

    if rangeOffset == 0 { 
     gids.append(contentsOf: charRange.map { charCode in 
      return (charCode + delta) & 0xFFFF 
     }) 
    } 
    else { 
     for charCode in charRange { 
      // ??? 
     } 
    } 
} 

:

예를 들어, 여기에 내가 어디보다 완벽한 좋습니다. 이것은 이상한 C 포인터를 사용하여 Glyph 인덱스를 검색하는 곳입니다. 문제는 단지 그것을 알아낼 수 없다는 것입니다. 실제로 이해 변수를 교체, 여기에 내가있어 무엇 :

for charCode in charRange { 
     Not too sure about this Actual value of idRangeOffset[i] 
       |       | 
       v       v 
    glyphIndex = *(&idRangeOffset[i] + rangeOffset/2 + (charCode - start)) 
       ^
        | 
       Or this 
} 

그 경로 깨달음에게 나를 이어질 수 밖에 어떤 스위프트 3 포인터 전문가가 있습니까? 어떤 도움이라도 대단히 감사하겠습니다! 내가 스위프트에 말씀으로 당신의 의사 C 코드 워드를 번역하면

+0

'glyphIndex'를 만드는 코드의 경우 바깥 괄호 안의 부분은 포인터를 생성합니다. 그 괄호 앞에 오는'*'는 그 포인터에 의해 * 지시 된 데이터를 얻는다. – Toby

+0

바깥 괄호 안의 첫 번째 비트'idRangeOffset [i]'는'idRangeOffset [i]'의 값의 주소를 취한다. C에서 이것은 포인터, 즉 다른 객체의 주소를 보유하는 변수입니다. 두 번째 부분 인'+ rangeOffset/2 + (charCode - start)'는 * 주소 *에 더 많은 값을 추가하여 이제 다른 곳을 가리킨다. – Toby

+0

어떻게 신속하게 정확하게 표현해야 하는가? 나는 두려워 할 생각이 전혀 없다. – Toby

답변

1

는,이 같은 것입니다 :

//"May not work" example, do no use this 
glyphIndex = withUnsafePointer(to: &idRangeOffset[i]) {idRangeOffsetPointer in 
//In some cases `idRangeOffsetPointer` can work as `&idRangeOffset[i]` in C... 
    (idRangeOffsetPointer + Int(rangeOffset)/2 + Int(charCode - start)).pointee 
    //To make pointer operation in Swift, all integers need to be `Int`, 
    //And to match the C-rule of integer operation, you need to cast each portion to `Int` before adding operation 
    //The equivalent to C's dereferencing operator `*` in Swift is `pointee` property 
} 

하지만이 때문에 복사에 복사/아웃 의미의 예상대로 작동하지 않을 수 있습니다 Swift 's inout 매개 변수의 스위프트는 단일 요소 idRangeOffset[i]을 포함하는 시간 영역을 생성 할 수 있으며 그 주소를 idRangeOffsetPointer으로 전달할 수 있으므로 포인터 연산의 결과가 시간 영역 근처를 가리킬 수 있으므로 전혀 쓸모가 없습니다.

포인터 작업으로 의미있는 결과를 얻으려면 배열의 모든 요소가 인접한 영역에 배치되도록 보장해야하는 상황에서 작업해야 할 수 있습니다.

또한 당신은 그 C-문을 알아야한다 :

glyphIndex = *(&idRangeOffset[i] + idRangeOffset[i]/2 + (c - startCode[i])) 

는 사실에 근거, 즉 전체 idRangeOffsetglyphIdArray는 틈새 나 패딩없이 인접 지역에 배치됩니다. 당신의 idRangeOffsetsegCount 요소가 포함되어있는 경우

그래서, 다음과 같은 코드가 작동하지 않을 것입니다 (난 당신이 형식 (4)에 대해 잘 알고 있다고 가정).

//"Should work" in a certain condition 
glyphIndex = idRangeOffset.withUnsafeBufferPointer{idRangeOffsetBufferPointer in 
    let idRangeOffsetPointer = idRangeOffsetBufferPointer.baseAddress! + i 
    //`idRangeOffsetPointer` is equivalent to `&idRangeOffset[i]` in C inside this closure 
    return (idRangeOffsetPointer + Int(rangeOffset)/2 + Int(charCode - start)).pointee 
} 

그러나 C의 포인터와 배열의 의미를 고려와

는 위의 코드는 여기에 해당합니다 :

glyphIndex = idRangeOffset[i + Int(rangeOffset)/2 + Int(charCode - start)] 

//`*(&arr[i] + n)` is equivalent to `arr[i + n]` in C 

내가 반복 idRangeOffset 및 glyphIdArray의 전체 내용을 포함 할 필요가 idRangeOffset배열 .

+0

좋아, 나는 우리가 가까워지고있는 것처럼 느낀다. 내 질문을 게시하기 전에, 나는'withUnsafeBufferPointer' 기법을 시도했지만 아무 소용이 없다. 그러나'idRangeOffset' 내용의 끝 부분에'glyphIndexArray'의 내용을 포함시켜야하므로, 하나의 긴 연속 배열이 될 것입니다. 이것은 기본 저장소가 힙 또는 어떤 것에 응집력있는 단위로 저장되도록 허용합니까? 내 무지를 용서해주세요. 내 Swift <=> C 게임은 내가 좋아할만큼 날카 롭지 않습니다. –

+0

_it의 하나의 긴 연속 배열? _ True. 수십만 개의 요소가 포함될 수 있습니다. _ 이것이 기본 저장소가 힙 또는 기타 메모리에 응집력있는 단위로 저장 될 수 있도록 허용합니까? - 엄격한 의미는 아니지만 ** 하위 항목 ** 또는 **을 통해 액세스 할 때 사실이라고 생각할 수 있습니다. withUnsafeBufferPointer' **. OmniProg의 답은 바이너리 데이터 형식에서 내용의 의미는 절대 위치 또는 오프셋에 따라 달라질 수 있습니다. 희망이 내 대답은 당신이 정확히 거기에 도움이 될 것입니다. – OOPer

0

@OOPer가 말한 것에 덧붙이면, 관심있는 전체 cmap 또는 서브 테이블을 메모리로 읽어 들이고 Swift에서 설명서를 지침으로 사용하여 작업하는 것이 좋습니다. 예를 들어 https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html을 참조하십시오. 또한 C 구현을 참조로 사용할 수도 있지만 숙련 된 C 프로그래머가 아니라면 좋은 경로는 아닙니다. C에서 너무 많이 미묘해서 당신을 물릴 수 있습니다. C에서는 포인터와 오프셋의 관점에서 cmap을 사용하는 것이 정말 편리합니다. 스위프트는 포인터 친화적이지 않으므로 테이블에 오프셋을 사용하는 것이 좋습니다. 다른 유형의 값으로 맵의 다른 부분을 해석하는 데 문제가 발생할 가능성이 있지만 적어도 포인터 매직을 다룰 필요는 없습니다.

+0

조언 해 주셔서 감사합니다. 나는 실제로 그것을 "빠른"방법으로 작업하고 다른 대부분의 테이블 (다른 Format 서브 테이블을 포함하여)을 위해 메모리에 모두로드하려고합니다. 이것이 내가 한 일입니다. 이 바보 같은 C 포인터 일은 지금 당장 나를 기다리고있는 유일한 것입니다. 포맷 4 파싱 이외에, 나는 정말로 좋은 것에 대해 기분이 좋습니다. 내가 가지고있는 모든 테이블은 좋은 값 유형이고, 나는 할 수있는 한 '게으른'데이터를로드하고 있으며, 실제로는 꽤 멋지다. 네 말에 전적으로 동의 해; 나는 당신이 그것을 가장 잘 말했듯이 너무 많은 C가 빠져 나오려고 노력한다 : 너무 많은 미묘함이있다! –