Вот спецификация стандарта C17:
7.24.2.3 Функция strcpy
Синопсис
#include <string.h>
char *strcpy(char * restrict s1,
const char * restrict s2);
Функция strcpy
копирует строку, на которую указывает s2
(включая завершающий нулевой символ), в массив, на который указывает s1
. Если копирование происходит между объектами, которые перекрываются, поведение не определено.
Returns
Функция strcpy
возвращает значение s1
.
Копирование строки в tt + 3
, которая содержит 8 байтов, в tt
действительно вызовет копирование между перекрывающимися объектами и, таким образом, имеет неопределенное поведение .
Тем не менее, поскольку место назначения находится перед источником, вероятно, что копия будет выполнена, как ожидалось, и первые 8 байтов tt
будут перезаписаны с "1726354"
и нулевым байтом. Байт со смещением 9
не изменяется и все еще имеет значение '4'
, поэтому ваш оператор printf
может выдать 7 - '4' + '5'
, то есть 8
, но стандарт C не гарантирует такое поведение.
На самом деле у вас есть еще один экземпляр неопределенного поведения, когда вы передаете значение типа size_t
для спецификатора преобразования %d
. size_t
имеет размер, отличный от int
в 64-битных системах, поэтому несоответствие типов также имеет неопределенное поведение. Вы можете обнаружить такую ошибку, увеличив уровень предупреждения компилятора: gcc -Wall -Wextra -Werror
или clang -Weverything -Werror
.
Вот исправленная версия, которая надежно выводит 8
:
#include <stdio.h>
#include <string.h>
int main(void) {
char tt[20] = "9081726354";
memmove(tt, tt + 3, strlen(tt + 3) + 1);
printf("%d\n", (int)strlen(tt) - tt[9] + '5');
return 0;
}
Обратите внимание, что значения size_t
могут быть переданы в printf
с помощью спецификатора преобразования %zu
или %zd
, но многие устаревшие системы не поддерживают это расширение C99.