代码之家  ›  专栏  ›  技术社区  ›  Cliff

NSString的UTF8String的CFString Equiv是什么?

  •  7
  • Cliff  · 技术社区  · 16 年前

      const UInt8 *myBuffer = [(NSString*)aRequest UTF8String];
    

      const UInt8 *myBuffer = (const UInt8 *)CFStringGetCStringPtr(aRequest, kCFStringEncodingUTF8);
    

    这一切都是在一个紧凑的单元测试中完成的,该测试使用CFNetwork API通过套接字编写一个示例HTTP请求。我有可用的ObjC代码,我正试图将其移植到C++。我正在逐渐用免费桥接的NS API呼叫来代替它们。到目前为止,一切都是一对一的,直到最后一行。这就像需要完成的最后一件作品。

    6 回复  |  直到 16 年前
        1
  •  14
  •   jlstrecker    12 年前

    NSString CFString (NS|CF)String

    它有助于理解如何 [@"..." UTF8String] 作品。这是一个私有的实现细节,所以这不是福音,而是基于观察到的行为。当你发送一个字符串时 UTF8String

    - (const char *)UTF8String
    {
      NSUInteger utf8Length = [self lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
      NSMutableData *utf8Data = [NSMutableData dataWithLength:utf8Length + 1UL];
      char *utf8Bytes = [utf8Data mutableBytes];
      [self     getBytes:utf8Bytes
               maxLength:utf8Length
              usedLength:NULL
                encoding:NSUTF8StringEncoding
                 options:0UL
                   range:NSMakeRange(0UL, [self length])
          remainingRange:NULL];
      return(utf8Bytes);
    }
    

    您不必担心处理缓冲区的内存管理问题 -UTF8String 返回是因为 NSMutableData 是自动发布的。

    字符串对象可以自由地以任何形式保存字符串的内容,因此无法保证其内部表示是最适合您需求的表示(在本例中为UTF8)。如果你只使用普通的C语言,你将不得不处理管理一些内存来保存可能需要的任何字符串转换。曾经简单的 -UTF8String

    大多数 NSString 实际上是在CoreFoundation中/与CoreFoundation一起实现的/ CFS管柱 CFStringRef -> -UTF8String NSString -UTF8String 大多数并发症与记忆管理有关。以下是我过去处理它的方法:

    void someFunction(void) {
      CFStringRef cfString; // Assumes 'cfString' points to a (NS|CF)String.
    
      const char *useUTF8StringPtr = NULL;
      UInt8 *freeUTF8StringPtr = NULL;
    
      CFIndex stringLength = CFStringGetLength(cfString), usedBytes = 0L;
    
      if((useUTF8StringPtr = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8)) == NULL) {
        if((freeUTF8StringPtr = malloc(stringLength + 1L)) != NULL) {
          CFStringGetBytes(cfString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', false, freeUTF8StringPtr, stringLength, &usedBytes);
          freeUTF8StringPtr[usedBytes] = 0;
          useUTF8StringPtr = (const char *)freeUTF8StringPtr;
        }
      }
    
      long utf8Length = (long)((freeUTF8StringPtr != NULL) ? usedBytes : stringLength);
    
      if(useUTF8StringPtr != NULL) {
        // useUTF8StringPtr points to a NULL terminated UTF8 encoded string.
        // utf8Length contains the length of the UTF8 string.
    
        // ... do something with useUTF8StringPtr ...
      }
    
      if(freeUTF8StringPtr != NULL) { free(freeUTF8StringPtr); freeUTF8StringPtr = NULL; }
    }
    

    上面的代码试图获取指向缓冲区的指针 CFS管柱 用于存储字符串的内容。如果 CFS管柱 CFStringGetCStringPtr() NULL 这显然是最好、最快的案例。如果由于某种原因无法获得该指针,请说 CFS管柱 将其内容编码为UTF16,然后分配一个缓冲区 malloc() 当它被转码为UTF8时,它足够大,可以包含整个字符串。然后,在函数结束时,它检查是否分配了内存 free()

    现在来介绍一些技巧和窍门。.. CFS管柱 “倾向于”(这是一个私有的实现细节,因此它可以并且确实在不同版本之间发生变化)将“简单”字符串编码为MacRoman,这是一种8位宽的编码。与UTF8一样,MacRoman是ASCII的超集,因此所有字符<128等同于它们的ASCII对应物(或者,换句话说,任何<128的字符都是ASCII)。在MacRoman中,字符>=128是“特殊”字符。它们都有Unicode等价物,往往是额外的货币符号和“扩展的西方”字符。看 Wikipedia - MacRoman CFS管柱 CFS管柱 编码值 kCFStringEncodingMacRoman , NSString 编码值 NSMacOSRomanStringEncoding )并不意味着它有字符>=128。如果 kCFString编码MacRoman 由返回的编码字符串 kCFStringEncodingASCII kCFStringEncodingUTF8 )编码表示。

    根据您的要求,您可以使用 kCFString编码MacRoman 而不是 CFStringGetCStringPtr() kCFString编码MacRoman CFStringGetCStringPtr(string, kCFStringEncodingMacRoman) malloc()

    CFIndex stringLength = CFStringGetLength(cfString), usedBytes = 0L;
    
    useUTF8StringPtr = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8);
    
    for(CFIndex idx = 0L; (useUTF8String != NULL) && (useUTF8String[idx] != 0); idx++) {
      if(useUTF8String[idx] >= 128) { useUTF8String = NULL; }
    }
    
    if((useUTF8String == NULL) && ((freeUTF8StringPtr = malloc(stringLength + 1L)) != NULL)) {
      CFStringGetBytes(cfString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', false, freeUTF8StringPtr, stringLength, &usedBytes);
      freeUTF8StringPtr[usedBytes] = 0;
      useUTF8StringPtr = (const char *)freeUTF8StringPtr;
    }
    

        2
  •  5
  •   Tim Cooper    14 年前

    在上面的示例代码中,出现了以下内容:

    CFIndex stringLength = CFStringGetLength(cfString)
    

    然后,stringLength被用来malloc()一个字节数加1的临时缓冲区。

    CFStringGetLength() malloc()

    也许我遗漏了一些东西,但为了绝对安全,当它们全部转换为UTF-8时,容纳N个任意Unicode字符所需的字节数最多为4*N。

        3
  •  3
  •   ianh    16 年前

    documentation :

    你应该使用 CFStringGetCString 如果 CFStringGetCStringPtr 回报 NULL .

        4
  •  2
  •   wolfrevo jlstrecker    9 年前

    CFStringGetBytes CFStringGetLength 为了简单起见,并进行了@Doug建议的更正。

    const char *useUTF8StringPtr = NULL;
    char *freeUTF8StringPtr = NULL;
    
    if ((useUTF8StringPtr = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8)) == NULL)
    {
        CFIndex stringLength = CFStringGetLength(cfString);
        CFIndex maxBytes = 4 * stringLength + 1;
        freeUTF8StringPtr = malloc(maxBytes);
        CFStringGetCString(cfString, freeUTF8StringPtr, maxBytes, kCFStringEncodingUTF8);
        useUTF8StringPtr = freeUTF8StringPtr;
    }
    
    // ... do something with useUTF8StringPtr... 
    
    if (freeUTF8StringPtr != NULL)
        free(freeUTF8StringPtr);
    
        5
  •  0
  •   Sixten Otto    16 年前

    如果它注定要用于插座,也许 CFStringGetBytes() 这会是你最好的选择吗?

    CFStringGetCStringPtr() 说:

    此函数要么在恒定时间内立即返回请求的指针,不进行内存分配和复制,要么返回 NULL 如果结果是后者,则调用一个替代函数,例如 CFStringGetCString

        6
  •  0
  •   yact    16 年前

    这里有一种打印CFStringRef的方法,这意味着我们从CFStringRef中得到一个以“\0”结尾的字符串:

    // from: http://lists.apple.com/archives/carbon-development/2001/Aug/msg01367.html
    // by Ali Ozer
    // gcc -Wall -O3 -x objective-c -fobjc-exceptions -framework Foundation test.c
    
    #import <stdio.h>
    #import <Foundation/Foundation.h>
    
    /*
    This function will print the provided arguments (printf style varargs) out to the console.
    Note that the CFString formatting function accepts "%@" as a way to display CF types.
    For types other than CFString and CFNumber, the result of %@ is mostly for debugging
    and can differ between releases and different platforms. Cocoa apps (or any app which
    links with the Foundation framework) can use NSLog() to get this functionality.
    */
    
    void show(CFStringRef formatString, ...) {
       CFStringRef resultString;
       CFDataRef data;
       va_list argList;
       va_start(argList, formatString);
       resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
       va_end(argList);
       data = CFStringCreateExternalRepresentation(NULL, resultString, 
       CFStringGetSystemEncoding(), '?');
       if (data != NULL) {
          printf ("%.*s\n", (int)CFDataGetLength(data), CFDataGetBytePtr(data));
          CFRelease(data);
       }
       CFRelease(resultString);
    }
    
    int main(void)
    {
    
       // To use:
       int age = 25;
       CFStringRef name = CFSTR("myname");
    
       show(CFSTR("Name is %@, age is %d"), name, age);
    
       return 0;
    }