두 개의 포맷 문자열이 호환되는지 확인하는 방법은?
예:
"Something %d" and "Something else %d" // Compatible
"Something %d" and "Something else %f" // Not Compatible
"Something %d" and "Something %d else %d" // Not Compatible
"Something %d and %f" and "Something %2$f and %1$d" // Compatible
이에 대한 C 기능이 있어야 한다고 생각했는데, 관련 검색 결과가 나오지 않습니다.제 말은 컴파일러가 포맷 문자열과 인수가 일치하는지 확인하고 있기 때문에 이를 확인하기 위한 코드는 이미 작성되어 있습니다.유일한 문제는 어떻게 부를 수 있느냐는 것입니다.
저는 Objective-C를 사용하고 있기 때문에 Objective-C 특정 솔루션이 있으면 괜찮습니다.
2개인 경우printf()
format strings compatible은 형식 구문 분석의 연습입니다.
C는 적어도 다음과 같은 표준 런타임 비교 함수가 없습니다.
int format_cmp(const char *f1, const char *f2); // Does not exist
형식은 다음과 같습니다."%d %f"
그리고."%i %e"
둘 다 기대한다는 점에서 분명히 양립할 수 있습니다.int
그리고.float/double
. 참고:float
진급하다, 진급하다, 진급하다, 진급하다, 진급.double
~하듯이short
그리고.signed char
진급하다, 진급하다, 진급하다, 진급하다, 진급.int
.
형식"%*.*f"
그리고."%i %d %e"
호환되지만 확실하지는 않습니다: 둘 다 기대합니다.int
,int
그리고.float/double
.
형식"%hhd"
그리고."%d"
둘 다 기대하고 있습니다int
, 비록 첫번째가 가치를 부여할지라도.signed char
인쇄하기 전에
형식"%d"
그리고."%u"
호환되지 않습니다.비록 많은 시스템들이 희망대로 작동할 지라도 말입니다.참고: 일반적으로char
로 승진할 것입니다.int
.
형식"%d"
그리고."%ld"
엄밀하게 호환되지 않습니다.32비트 시스템에는 이와 동등한 것이 있지만 일반적인 것은 아닙니다.물론 코드는 이를 수용하기 위해 변경될 수 있습니다.오토"%lf"
그리고."%f"
의 통상적인 논쟁 홍보로 인해 호환됩니다.float
로.double
.
형식"%lu"
그리고."%zu"
호환될 수도 있지만, 그것은 구현에 달려 있습니다.unsigned long
그리고.size_t
. 코드에 추가하면 이와 관련된 동등성이 허용될 수 있습니다.
수식어와 지정자의 일부 조합은 다음과 같이 정의되지 않습니다."%zp"
. 다음은 이러한 난해한 조합을 허용하지 않지만 비교합니다.
수식어는 다음과 같습니다."$"
는 표준 C에 대한 확장이며 다음에서는 구현되지 않습니다.
에 대한 호환성 테스트printf()
다르다scanf()
.
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
typedef enum {
type_none,
type_int,
type_unsigned,
type_float,
type_charpointer,
type_voidpointer,
type_intpointer,
type_unknown,
type_type_N = 0xFFFFFF
} type_type;
typedef struct {
const char *format;
int int_queue;
type_type type;
} format_T;
static void format_init(format_T *state, const char *format);
static type_type format_get(format_T *state);
static void format_next(format_T *state);
void format_init(format_T *state, const char *format) {
state->format = format;
state->int_queue = 0;
state->type = type_none;
format_next(state);
}
type_type format_get(format_T *state) {
if (state->int_queue > 0) {
return type_int;
}
return state->type;
}
const char *seek_flag(const char *format) {
while (strchr("-+ #0", *format) != NULL)
format++;
return format;
}
const char *seek_width(const char *format, int *int_queue) {
*int_queue = 0;
if (*format == '*') {
format++;
(*int_queue)++;
} else {
while (isdigit((unsigned char ) *format))
format++;
}
if (*format == '.') {
if (*format == '*') {
format++;
(*int_queue)++;
} else {
while (isdigit((unsigned char ) *format))
format++;
}
}
return format;
}
const char *seek_mod(const char *format, int *mod) {
*mod = 0;
if (format[0] == 'h' && format[1] == 'h') {
format += 2;
} else if (format[0] == 'l' && format[1] == 'l') {
*mod = ('l' << CHAR_BIT) + 'l';
format += 2;
} else if (strchr("ljztL", *format)) {
*mod = *format;
format++;
} else if (strchr("h", *format)) {
format++;
}
return format;
}
const char *seek_specifier(const char *format, int mod, type_type *type) {
if (strchr("di", *format)) {
*type = type_int;
format++;
} else if (strchr("ouxX", *format)) {
*type = type_unsigned;
format++;
} else if (strchr("fFeEgGaA", *format)) {
if (mod == 'l') mod = 0;
*type = type_float;
format++;
} else if (strchr("c", *format)) {
*type = type_int;
format++;
} else if (strchr("s", *format)) {
*type = type_charpointer;
format++;
} else if (strchr("p", *format)) {
*type = type_voidpointer;
format++;
} else if (strchr("n", *format)) {
*type = type_intpointer;
format++;
} else {
*type = type_unknown;
exit(1);
}
*type |= mod << CHAR_BIT; // Bring in modifier
return format;
}
void format_next(format_T *state) {
if (state->int_queue > 0) {
state->int_queue--;
return;
}
while (*state->format) {
if (state->format[0] == '%') {
state->format++;
if (state->format[0] == '%') {
state->format++;
continue;
}
state->format = seek_flag(state->format);
state->format = seek_width(state->format, &state->int_queue);
int mod;
state->format = seek_mod(state->format, &mod);
state->format = seek_specifier(state->format, mod, &state->type);
return;
} else {
state->format++;
}
}
state->type = type_none;
}
// 0 Compatible
// 1 Not Compatible
// 2 Not Comparable
int format_cmp(const char *f1, const char *f2) {
format_T state1;
format_init(&state1, f1);
format_T state2;
format_init(&state2, f2);
while (format_get(&state1) == format_get(&state2)) {
if (format_get(&state1) == type_none)
return 0;
if (format_get(&state1) == type_unknown)
return 2;
format_next(&state1);
format_next(&state2);
}
if (format_get(&state1) == type_unknown)
return 2;
if (format_get(&state2) == type_unknown)
return 2;
return 1;
}
참고: 최소한의 테스트만 수행됩니다.추가적으로 고려해야 할 사항들이 많이 추가될 수 있습니다.
알려진 단점:hh,h,l,ll,j,z,t
의 수식어.n
.l
와 함께s,c
.
[편집]
보안 문제에 대한 OP의 의견.이것은 게시물의 성격과 비교를 동등한 것에서 보안적인 것으로 바꿉니다.패턴(A) 중 하나는 기준 패턴이고 다음(B)는 테스트라고 생각합니다.테스트는 "B가 적어도 A만큼 안전한가?"입니다.예A = "%.20s"
그리고.B1 = "%.19s"
,B2 = "%.20s"
,B3 = "%.21s"
.B1
그리고.B2
합니다 20더지기에안를다를다를안ehetysstety더에0다o기0하지char
.B3
㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛ ㎛char
. 또한 다음과 같이 자격을 갖춘 비폭.%s %[ %c
참조 또는 테스트 패턴에 보안 문제가 있습니다.이 답변의 코드는 이 문제를 해결하지 못합니다.
바와 같이, 한 는 를 하지 와 하지 한 를 와 "%n"
.
[2018 편집]
" " " 관련"%d"
그리고."%u"
호환되지 않습니다.": 일반적으로 인쇄할 값입니다.의우우의 [0..INT_MAX]
C11dr ≥ 6C11dr ≥ 6.5.2.26 ≥ 6.5.2.26 ≤ 1.5 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 ≤ 1.2 %
제가 알기로는 기본적으로 두 개의 문자열을 보고 둘 다 같은 종류의 값을 가지는지 탐지할 수 있는 방법을 원하신다고 생각합니다.아니면 그 선들을 따라 뭔가..그렇다면 이 방법(또는 이 방법에 따라).
-(int)checkCompatible:(NSString *)string_1 :(NSString *)string_2 {
// Separate the string into single elements.
NSArray *stringArray_1 = [string_1 componentsSeparatedByString:@" "];
NSArray *stringArray_2 = [string_2 componentsSeparatedByString:@" "];
// Store only the numbers for comparison in a new array.
NSMutableArray *numbers_1 = [[NSMutableArray alloc] init];
NSMutableArray *numbers_2 = [[NSMutableArray alloc] init];
// Make sure the for loop below, runs for the appropriate
// number of cycles depending on which array is bigger.
int loopMax = 0;
if ([stringArray_1 count] > [stringArray_2 count]) {
loopMax = (int)[stringArray_1 count];
}
else {
loopMax = (int)[stringArray_2 count];
}
// Now go through the stringArray's and store only the
// numbers in the mutable array's. This will be used
// during the comparison stage.
for (int loop = 0; loop < loopMax; loop++) {
NSCharacterSet *notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if (loop < [stringArray_1 count]) {
if ([[stringArray_1 objectAtindex:loop] rangeOfCharacterFromSet:notDigits].location == NSNotFound) {
// String consists only of the digits 0 through 9.
[numbers_1 addObject:[stringArray_1 objectAtindex:loop]];
}
}
if (loop < [stringArray_2 count]) {
if ([[stringArray_2 objectAtindex:loop] rangeOfCharacterFromSet:notDigits].location == NSNotFound) {
// String consists only of the digits 0 through 9.
[numbers_2 addObject:[stringArray_2 objectAtindex:loop]];
}
}
}
// Now look through the mutable array's
// and perform the type comparison,.
if ([numbers_1 count] != [numbers_2 count]) {
// One of the two strings has more numbers
// than the other, so they are NOT compatible.
return 1;
}
else {
// Both string have the same number of numbers
// numbers so lets go through them to make
// sure the numbers are of the same type.
for (int loop = 0; loop < [numbers_1 count]; loop++) {
// Check to see if the number in the current array index
// is a float or an integer. All the numbers in the array have
// to be the SAME type, in order for the strings to be compatible.
BOOL check_float_1 = [[NSScanner scannerWithString:[numbers_1 objectAtindex:loop]] scanFloat:nil];
BOOL check_int_1 = [[NSScanner scannerWithString:[numbers_1 objectAtindex:loop]] scanInt:nil];
BOOL check_float_2 = [[NSScanner scannerWithString:[numbers_2 objectAtindex:loop]] scanFloat:nil];
BOOL check_int_2 = [[NSScanner scannerWithString:[numbers_2 objectAtindex:loop]] scanInt:nil];
if (check_float_1 == YES) {
if (check_float_2 == NO) {
return 1;
}
}
else if (check_int_1 == YES) {
if (check_int_2 == NO) {
return 1;
}
}
else {
// Error of some sort......
return 1;
}
}
// All the numbers in the strings are of the same
// type (otherwise we would NOT have reached
// this point). Therefore the strings are compatible.
return 0;
}
}
언급URL : https://stackoverflow.com/questions/28947528/how-to-check-that-two-format-strings-are-compatible
'programing' 카테고리의 다른 글
EditText 깜박이는 커서 사용 안 함 (0) | 2023.09.06 |
---|---|
날짜로부터 두 개의 mariadb 데이터베이스를 동기화하려면 어떻게 해야 합니까? (0) | 2023.09.06 |
MySQL/MariaDB 오류가 발생하도록 경고 구성 (0) | 2023.09.06 |
Jenkins Pipeline Git SCM 자격 증명 확인? (0) | 2023.09.01 |
Spring MVC에서 AJAX를 사용하여 뷰를 렌더링하는 방법 (0) | 2023.09.01 |