是否保证 std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?
Is it guaranteed that std::char_traits<char>::to_int_type(c) == static_cast<int>(c)?
问题How to use correctly the return value from std::cin.get()
and std::cin.peek()
?让我想知道是否保证
std::char_traits<char>::to_int_type(c) == static_cast<int>(c)
对于所有有效 char
值 c
。
这在很多地方都会出现。例如,istream::peek
调用 streambuf::sgetc
,后者使用 to_int_type
将 char
值转换为 int_type
。现在,std::cin.peek() == '\n'
真的意味着下一个字符是 \n
吗?
这是我的分析。让我们收集 [char.traits.require] and [char.traits.specializations.char]:
的碎片
对于每个 int
值 e
、to_char_type(e)
returns
c
,如果 eq_int_type(e, to_int_type(c))
对于某些 c
;
一些未指定的值。
对于每对 int
值 e
和 f
,eq_int_type(e, f)
returns
eq(c, d)
,如果 e == to_int_type(c)
和 f == to_int_type(d)
对于某些 c
和 d
;
true
,如果e == eof()
和f == eof()
;
false
, 如果 e == eof()
xor f == eof()
;
未另行说明。
eof()
returns 一个值 e
这样 !eq_int_type(e, to_int_type(c))
对于所有 c
.
eq(c, d)
当且仅当(unsigned char) c == (unsigned char) d
.
现在,考虑这个假设的实现:(语法简化)
// char: [-128, 127]
// unsigned char: [0, 255]
// int: [-2^31, 2^31-1]
#define EOF INT_MIN
char to_char_type(int e) {
return char(e - 1);
}
int to_int_type(char c) {
return int(c) + 1;
}
bool eq(char c, char d) {
return c == d;
}
bool eq_int_type(int c, int d) {
return c == d;
}
int eof() {
return EOF;
}
注意
(属性 1)从unsigned char
到int
的转换是保值的;
(属性 2) 从char
到unsigned char
的转换是双射的。
现在让我们验证要求:
对于每个 int
值 e
,如果 eq_int_type(e, to_int_type(c))
对于某些 c
,则 e == int(c) + 1
。因此,to_char_type(e) == char(int(c)) == c
.
对于每对 int
值 e
和 f
,如果 e == to_int_type(c)
和 f == to_int_type(d)
对于某些 c
和 d
,然后 eq_int_type(e, f)
当且仅当 int(c) + 1 == int(d) + 1
当且仅当 c == d
(由 属性 1)。 EOF 案例也很容易验证。
对于每个 char
值 c
、int(c) >= -128
,所以 int(c) + 1 != EOF
。因此,!eq_int_type(eof(), to_int_type(c))
.
对于每对 char
值 c
和 d
,eq(c, d)
当且仅当 (unsigned char) c == (unsigned char d)
(通过 属性 2).
这是否意味着此实现符合要求,因此 std::cin.peek() == '\n'
没有做它应该做的事情?我在分析中遗漏了什么吗?
Does that mean this implementation is conforming, and therefore std::cin.peek() == '\n' does not do what it is supposed to do?
我同意你的分析。这不能保证。
看来您必须使用 eq_int_type(std::cin.peek(), to_int_type('\n'))
来保证正确的结果。
P.S。由于 INT_MIN - 1
中的签名溢出,您的 to_char_type(EOF)
有未定义的行为。当然,在这种情况下该值未指定,但您仍然不能拥有 UB。这将是有效的:
char to_char_type(int e) {
return e == EOF
? 0 // doesn't matter
: char(e - 1);
}
to_int_type
在 c == INT_MAX
的情况下,在 int 和 char 大小相同的系统上会有 UB,但您已经排除了那些具有假设大小的系统。
问题How to use correctly the return value from std::cin.get()
and std::cin.peek()
?让我想知道是否保证
std::char_traits<char>::to_int_type(c) == static_cast<int>(c)
对于所有有效 char
值 c
。
这在很多地方都会出现。例如,istream::peek
调用 streambuf::sgetc
,后者使用 to_int_type
将 char
值转换为 int_type
。现在,std::cin.peek() == '\n'
真的意味着下一个字符是 \n
吗?
这是我的分析。让我们收集 [char.traits.require] and [char.traits.specializations.char]:
的碎片对于每个
int
值e
、to_char_type(e)
returnsc
,如果eq_int_type(e, to_int_type(c))
对于某些c
;一些未指定的值。
对于每对
int
值e
和f
,eq_int_type(e, f)
returnseq(c, d)
,如果e == to_int_type(c)
和f == to_int_type(d)
对于某些c
和d
;true
,如果e == eof()
和f == eof()
;false
, 如果e == eof()
xorf == eof()
;未另行说明。
eof()
returns 一个值e
这样!eq_int_type(e, to_int_type(c))
对于所有c
.eq(c, d)
当且仅当(unsigned char) c == (unsigned char) d
.
现在,考虑这个假设的实现:(语法简化)
// char: [-128, 127]
// unsigned char: [0, 255]
// int: [-2^31, 2^31-1]
#define EOF INT_MIN
char to_char_type(int e) {
return char(e - 1);
}
int to_int_type(char c) {
return int(c) + 1;
}
bool eq(char c, char d) {
return c == d;
}
bool eq_int_type(int c, int d) {
return c == d;
}
int eof() {
return EOF;
}
注意
(属性 1)从
unsigned char
到int
的转换是保值的;(属性 2) 从
char
到unsigned char
的转换是双射的。
现在让我们验证要求:
对于每个
int
值e
,如果eq_int_type(e, to_int_type(c))
对于某些c
,则e == int(c) + 1
。因此,to_char_type(e) == char(int(c)) == c
.对于每对
int
值e
和f
,如果e == to_int_type(c)
和f == to_int_type(d)
对于某些c
和d
,然后eq_int_type(e, f)
当且仅当int(c) + 1 == int(d) + 1
当且仅当c == d
(由 属性 1)。 EOF 案例也很容易验证。对于每个
char
值c
、int(c) >= -128
,所以int(c) + 1 != EOF
。因此,!eq_int_type(eof(), to_int_type(c))
.对于每对
char
值c
和d
,eq(c, d)
当且仅当(unsigned char) c == (unsigned char d)
(通过 属性 2).
这是否意味着此实现符合要求,因此 std::cin.peek() == '\n'
没有做它应该做的事情?我在分析中遗漏了什么吗?
Does that mean this implementation is conforming, and therefore std::cin.peek() == '\n' does not do what it is supposed to do?
我同意你的分析。这不能保证。
看来您必须使用 eq_int_type(std::cin.peek(), to_int_type('\n'))
来保证正确的结果。
P.S。由于 INT_MIN - 1
中的签名溢出,您的 to_char_type(EOF)
有未定义的行为。当然,在这种情况下该值未指定,但您仍然不能拥有 UB。这将是有效的:
char to_char_type(int e) {
return e == EOF
? 0 // doesn't matter
: char(e - 1);
}
to_int_type
在 c == INT_MAX
的情况下,在 int 和 char 大小相同的系统上会有 UB,但您已经排除了那些具有假设大小的系统。