9 votes

Existe-t-il un strlen() qui fonctionne avec les char16_t ?

Comme le dit la question :

typedef __CHAR16_TYPE__ char16_t; 

int main(void)
{
  static char16_t test[] = u"Hello World!\n";

  printf("Length = %d", strlen(test)); // strlen equivalent for char16_t ???

  return 0;
}

J'ai cherché et trouvé uniquement des solutions C++.

Mon compilateur est GCC 4.7 .

Edit :

Pour clarifier, je cherchais une solution qui retourne le nombre de code points et non le nombre de characters .

Ces deux éléments sont très différents pour UTF-16 les chaînes de caractères contenant des caractères en dehors du BMP .

6voto

askmish Points 3411

Voici votre strlen de base :

int strlen16(const char16_t* strarg)
{
   int count = 0;
   if(!strarg)
     return -1; //strarg is NULL pointer
   char16_t* str = strarg;
   while(*str)
   {
      count++;
      str++;
   }
   return count;
}

Voici un strlen plus efficace et plus populaire :

int strlen16(const char16_t* strarg)
{
   if(!strarg)
     return -1; //strarg is NULL pointer
   char16_t* str = strarg;
   for(;*str;++str)
     ; // empty body
   return str-strarg;
}

J'espère que cela vous aidera.

Attention : Cela ne fonctionne pas correctement lorsque l'on compte les caractères (et non les points de code) d'une chaîne UTF-16. C'est particulièrement vrai lorsque __STDC_UTF_16__ est défini comme suit 1 .

UTF-16 est de longueur variable (2 octets par caractère dans le BMP ou 4 octets par caractère en dehors du BMP) et n'est pas couvert par ces fonctions.

6voto

Raven Points 429

std::char_traits a ceci.

#include <string>

std::char_traits<char16_t>::length(yourchar16pointerhere);

3voto

Hypersoft Systems Points 276
#include <string.h>
#include <wchar.h>
#include <uchar.h>

#define char8_t char
#define strlen8 strlen
#define strlen16 strlen16
#define strlen32(s) wcslen((const wchar_t*)s)

static inline size_t strlen16(register const char16_t * string) {
    if (!string) return 0;
    register size_t len = 0;
    while(string[len++]);
    return len;
}

Vous devez vous attendre à ce que le nombre de char16_t caractères à renvoyer, par opposition au nombre d'octets.

Visualisation de l'assemblage Intel Atom 32 bits optimisé :

gcc -Wpedantic -std=iso9899:2011 -g3 -O2 -MMD -faggressive-loop-optimizations -fkeep-inline-functions -march=atom -mtune=atom -fomit-frame-pointer -mssse3 -mieee-fp -mfpmath=sse -fexcess-precision=fast -mpush-args -mhard-float -fPIC ...

.Ltext0:
    .p2align 4,,15
    .type   strlen16, @function
strlen16:
.LFB20:
    .cfi_startproc
.LVL0:
    mov edx, DWORD PTR 4[esp]
    xor eax, eax
    test    edx, edx
    je  .L4
    .p2align 4,,15
.L3:
.LVL1:
    lea eax, 1[eax]
.LVL2:
    cmp WORD PTR -2[edx+eax*2], 0
    jne .L3
    ret
.LVL3:
    .p2align 4,,7
    .p2align 3
.L4:
    ret
    .cfi_endproc
.LFE20:
    .size   strlen16, .-strlen16

Voici un démontage d'Intel :

static inline size_t strlen16(register const char16_t * string) {
   0:   8b 54 24 04             mov    edx,DWORD PTR [esp+0x4]
    if (!string) return 0;
   4:   31 c0                   xor    eax,eax
   6:   85 d2                   test   edx,edx
   8:   74 16                   je     20 <strlen16+0x20>
   a:   8d b6 00 00 00 00       lea    esi,[esi+0x0]
    register size_t len = 0;
    while(string[len++]);
  10:   8d 40 01                lea    eax,[eax+0x1]
  13:   66 83 7c 42 fe 00       cmp    WORD PTR [edx+eax*2-0x2],0x0
  19:   75 f5                   jne    10 <strlen16+0x10>
  1b:   c3                      ret    
  1c:   8d 74 26 00             lea    esi,[esi+eiz*1+0x0]
    return len;
}
  20:   c3                      ret    
  21:   eb 0d                   jmp    30 <AnonymousFunction0>
  23:   90                      nop
  24:   90                      nop
  25:   90                      nop
  26:   90                      nop
  27:   90                      nop
  28:   90                      nop
  29:   90                      nop
  2a:   90                      nop
  2b:   90                      nop
  2c:   90                      nop
  2d:   90                      nop
  2e:   90                      nop
  2f:   90                      nop

0voto

Alex Points 3551

Vous devez lire 2 octets et vérifier si les deux sont des zéros, car en unicode le premier octet peut être zéro.

Ce n'est pas une solution parfaite (en fait, c'est une solution plutôt bizarre) :

size_t strlen16(const char16_t* str16) {
    size_t result = 0;
    char* strptr = (char*) str16;
    char byte0, byte1;

    if(str16 == NULL) return result;

    byte0 = *strptr;
    byte1 = *(strptr + 1);

    while(byte0|byte1) {
        strptr += 2;
        byte0 = *strptr;
        byte1 = *(strptr + 1);
        result++;
    }
    return result;
}

0voto

Pavel Radzivilovsky Points 11613

Sous Windows, il y a wcslen() .

Quelle que soit la plate-forme, il vaut mieux ne pas utiliser de char16_t. Je crois que c'est un bévue de la part du comité de normalisation de l'avoir dans la langue.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X