English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
MySQL에서는 자주 동적 문자열 처리에 대한 것을 볼 수 있습니다. 예를 들어: DYNAMIC_STRING.
동적 문자열의 실제 길이, 버퍼의 최대 길이, 문자열이 조정될 때마다 새로운 메모리를 할당하고 길이를 조정하는 것을 기록하기 위해 MySQL은 DYNAMIC_STRING를 사용하여 동적 문자열 관련 정보를 저장합니다:
typedef struct st_dynamic_string { char *str; size_t length, max_length, alloc_increment; }; DYNAMIC_STRING;
이 구조체에서 str은 실제 문자열의 첫 번째 주소를 저장하고, length는 문자열의 실제 길이를 기록하며, max_length는 문자열 버퍼가 최대로 저장할 수 있는 문자 수를 기록하며, alloc_increment은 문자열이 메모리를 할당받을 때마다 얼마씩 메모리를 할당할지를 나타냅니다.
이 구조체의 초기화 과정을 확인해 보겠습니다:
my_bool init_dynamic_string( DYNAMIC_STRING *str, const char *init_str, size_t init_alloc, size_t alloc_increment ) { size_t length; DBUG_ENTER( "init_dynamic_string" ); if ( !alloc_increment ) alloc_increment = 128; length = 1; if ( init_str && (length = strlen( init_str ) + 1) < init_alloc ) init_alloc = ( (length + alloc_increment - 1) / alloc_increment) * alloc_increment; if ( !init_alloc ) init_alloc = alloc_increment; if (!(str->str = (char *) my_malloc( init_alloc, MYF( MY_WME ) ) ) ) DBUG_RETURN( TRUE ); str->length = length - 1; if ( init_str ) memcpy(str->str, init_str, length ); str->max_length = init_alloc; str->alloc_increment = alloc_increment; DBUG_RETURN( FALSE ); }
위 함수에서 보면, 초기화할 때, 초기 할당된 문자열 버퍼 크기 init_alloc는 필요한 문자열에 따라 판단됩니다. 이 DYNAMIC_STRING 공간이 할당된 후, 버퍼 크기, 문자열의 실제 길이, alloc_increment를 기준으로 초기화합니다:
length:문자열의 실제 길이
max_length:버퍼의 최대 길이
alloc_increment:공간이 부족할 때 다음에 메모리를 할당할 단위 크기.
이 내용을 초기화한 후, 다음에 이 버퍼에 더 많은 문자를 추가해야 한다면, 이 값을 기준으로 버퍼를 확장할 필요가 있는지 판단할 수 있습니다:
my_bool dynstr_append_mem( DYNAMIC_STRING *str, const char *append, size_t length ) { char *new_ptr; if (str->length + length >= str->max_length) /* 추가된 문자열이 버퍼 크기를 초과하면 */ { /* 필요한 alloc_increment 크기의 메모리를 얼마나 할당해야 추가된 문자열을 저장할 수 있을까요? */ size_t new_length = (str->length + length + str->alloc_increment) / str->alloc_increment; new_length *= str->alloc_increment; if ( !(new_ptr = (char *) my_realloc(str->str, new_length, MYF( MY_WME ) ) ) ) return(TRUE); str->str = new_ptr; str->max_length = new_length; } /* 将新分配的内容,append到str之后 */ memcpy(str->str + str->length, append, length ); str->length += length; /* 扩容之后str新的长度 */ str->str[str->length] = 0; /* Safety for C programs */ /* 字符串最后一个字符为'\0' */ return(FALSE); }
从上述代码可以看到,在字符串初始化化好之后,之后如果需要给该字符串增加新的内容,只需要根据之前存储的信息来动态的realloc就好了。由于该结构体记录了字符串相关的完整内容,所以动态的扩容会非常方便处理。
当然,除了这些,还有比如字符串截断,字符串初始设置,转义OS的引号等等:
将字符串偏移大于N之后的截断。
my_bool dynstr_trunc(DYNAMIC_STRING *str, size_t n ) { str->length -= n; str->str[str->length] = '\0'; return(FALSE); }
返回字符串中第一次出现某个字符的地址。若没有,则返回字符串结尾的地址(指向'')
char *strcend(register const char *s, register pchar c ) { for (;; ) { if ( *s == (char)c ) return((char *) s); if (!*s++ ) return((char *) s - 1); } }
字符串内容扩容:
my_bool dynstr_realloc(DYNAMIC_STRING *str, size_t additional_size) { DBUG_ENTER("dynstr_realloc"); if (!additional_size) DBUG_RETURN( FALSE ); if (str->length + additional_size > str->max_length) /* 如果新的字符串内容超过缓冲区的最大长度 */ { str->max_length = ((str->length + additional_size + str->alloc_increment - 1) / str->alloc_increment) * str->alloc_increment; if (!(str->str = (char *) my_realloc(str->str, str->max_length, MYF(MY_WME)) DBUG_RETURN( TRUE ); } DBUG_RETURN( FALSE ); }
Enclose the string in quotes, escape the single quotes within, mainly used to execute some system commands (system(cmd)).
for example: ls -al will become 'ls' -al'
for example: ls -a'l will become 'ls' -a\'l'
/* * Concatenates any number of strings, escapes any OS quote in the result then * surround the whole affair in another set of quotes which is finally appended * to specified DYNAMIC_STRING. This function is especially useful when * building strings to be executed with the system() function. * * @param str Dynamic String which will have addtional strings appended. * @param append String to be appended. * @param ... Optional. Additional string(s) to be appended. * * @ note The final argument in the list must be NullS even if no additional * options are passed. * * @return True = Success. */ my_bool dynstr_append_os_quoted( DYNAMIC_STRING *str, const char *append, ... ) { const char *quote_str = "'"; const uint quote_len = 1; my_bool ret = TRUE; va_list dirty_text; ret &= dynstr_append_mem( str, quote_str, quote_len ); /* Leading quote */ va_start( dirty_text, append ); while ( append != NullS ) { const char *cur_pos = append; const char *next_pos = cur_pos; /* 각 문자열에서 quote를 찾아 escape된 quote로 대체합니다 */ while ( *(next_pos = strcend( cur_pos, quote_str[0] ) ) != '\0' ) { ret &= dynstr_append_mem( str, cur_pos, (uint) (next_pos - cur_pos) ); ret &= dynstr_append_mem( str, "\\", 1 ); ret &= dynstr_append_mem( str, quote_str, quote_len ); cur_pos = next_pos + 1; } ret &= dynstr_append_mem( str, cur_pos, (uint) (next_pos - cur_pos) ); append = va_arg( dirty_text, char * ); } va_end( dirty_text ); ret &= dynstr_append_mem( str, quote_str, quote_len ); /* Trailing quote */ return(ret); }
동적 문자열 구조체 정보를 정의하여, 문자열에 더 많은 문자를 추가할 때마다 문자열의 현재 길이에 따라 동적으로 확장됩니다. 그리고 각 번째 확장 후, 해당 구조체는 현재 문자열의 실제 정보(현재 문자열의 길이, 버퍼가 문자열을 저장할 수 있는 길이, 확장 단위 길이)를 기록합니다. 이렇게 하면 동적 문자열 처리 작업이 매우 편리해집니다.
선언: 본 내용은 인터넷에서 가져왔으며, 저작권자의 소유물입니다. 내용은 인터넷 사용자가 자발적으로 기여하고 업로드한 것이며, 이 사이트는 소유권을 가지지 않으며, 인공 편집 처리를 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 침해 내용을 발견한 경우, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com(메일을 보내는 경우, #을 @으로 변경하여 신고해 주시고, 관련 증거를 제공해 주시면, 사이트가 즉시 저작권 침해 내용을 삭제할 것입니다.