#c #c 11 #gdb
#c #c 11 #gdb
Вопрос:
У меня есть sscanf
оператор, который ведет себя неожиданно. Это где-то около цикла # 8000, когда он внезапно делает это. Это код, в котором str
строка анализируется из файла:
char a1[6], a2[6], op[6], a3[6];
int success = sscanf(str.c_str(),"%*s %s %*s %s %s %s",a1, a2, op, a3);
И это вывод gdb в проблемной строке ( str
is "assign po012 = po011;"
):
(gdb) print str
$9 = {<std::__1::__basic_string_common<true>> = {<No data fields>}, static __short_mask = 1, static __long_mask = 1,
__r_ = {<std::__1::__compressed_pair_elem<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__rep, 0, false>> = {__value_ = {{__l = {__cap_ = 97, __size_ = 23, __data_ = 0x1003001d0 " assign po012 = po011;"}, __s = {{
__size_ = 97 'a', __lx = 97 'a'},
__data_ = "000000000000002700000000000000320016000010000"}, __r = {__words = {
97, 23,
4298113488}}}}}, <std::__1::__compressed_pair_elem<std::__1::allocator<char>, 1, true>> = {<std::__1::allocator<char>> = {<No data fields>}, <No data fields>}, <No data fields>}, static npos = 18446744073709551615}
(gdb) n
81 string A1(a1);
(gdb) print a1
$10 = "00o012"
(gdb) print a2
$13 = "po011;"
a2
имеет ожидаемое значение, но что происходит a1
только в этом одном случае?
Комментарии:
1. почему он имеет a
''
вместо'p
‘? понятия не имею, но попробуйте установить контрольную точку наa1[0]
2.
sscanf
этоC
не APIC
.3. Все работает так, как должно быть, и так, как это задокументировано: godbolt.org/z/offP9K
4. Показанное
str
значение не соответствуетsscanf
искомому шаблону.
Ответ №1:
Ваши массивы имеют длину шесть:
char a1[6], a2[6], op[6], a3[6];
Тем не менее, sscanf
вызывает "po011;"
запись a2
, и для этого требуется семь символов, поскольку sscanf
добавит нулевой терминатор. Следовательно, sscanf
вызывает неопределенное поведение.
Прагматично, в вашей реализации нулевой терминатор был добавлен в начало a1
, которое изменилось с предполагаемого "po012"
на "00o012"
(начальное p
было перезаписано). Похоже, ваша реализация решила сохранить a1
сразу после a2
, поэтому переполнение a2
перезаписано a1
. Это одна из вещей, которые могут произойти, когда запускается неопределенное поведение.
Комментарии:
1. Я увеличил длину массива символов до 8, без какого-либо эффекта. Первоначальный запуск был на моем mac, но когда я клонировал на машине RHEL, он работал. Вы знаете, почему это изменило его?
2. увеличение длины массива до 10 исправило его на mac, я думаю, что описанный вами механизм верен. Спасибо!
3. @CaitlinSlicker Я не могу четко понять, что происходит в вашем коде. Может быть, в вашем файле есть более длинное поле? Изменение ОС / компилятора также может привести к тому, что неопределенное поведение может случайно «работать», как ожидалось, но на это не следует полагаться, поскольку оно может перестать работать в любой момент. Убедитесь, что в файле поля достаточно длинные. Вы также можете использовать спецификатор формата с размером строки, например
%9s
, для предотвращения переполнения буфера. Кроме того, в C вы могли бы избежать scanf и вместо этого работать с std::string .