strstr: поведение отличается при использовании разных версий gcc - PullRequest
3 голосов
/ 23 сентября 2011

Я портирую программу, которая работает с Ubuntu 8.04 (gcc версия 4.2.4), на 10.04 (gcc версия 4.4.3).У меня есть следующий код:

#include <stdio.h>
#include <string.h>

int main(void) {
  char p[100] = "////abcd";
  char *t;

  /* Remove duplicate slashes, saving only one of them */
  while (t = strstr(p, "//"))
    strcpy(t, t + 1);

  printf("%s\n", p);

  return 0;
}

Результат должен быть /abcd, что с gcc 4.2.4.В 4.4.3 выводом является /accd.

. Можете ли вы предложить мне изменение кода, которое даст правильный вывод при использовании обеих версий gcc, и предпочтительно объясните, что здесь происходит.

Заранее спасибо!

1 Ответ

7 голосов
/ 23 сентября 2011

Вам только что повезло.

Из документации strcpy:

Функция strcpy () копирует строку, на которую указываетs2 (включая завершающий нулевой байт) в массив, на который указывает s1. Если копирование происходит между объектами, которые перекрываются, поведение не определено.

В вашем случае строки перекрываются, ваша программа вызывает неопределенное поведение.

ВозможноПричина, по которой он работал, но больше не работает, заключается в том, что strcpy мог быть реализован GCC как встроенный, например memmove (то есть безопасен в этой ситуации), но это изменилось на небезопасную версию по соображениям производительности.(Это чистое предположение.)

Чтобы исправить это, используйте memmove вместо strcpy, например:

while (t = strstr(p, "//")) {
  memmove(t, t+1, strlen(t)); // strlen(t)'s bytes worth of data
                              // will cover the string bytes left
                              // and the \0 terminator
}

Это не очень эффективно, но это будет работать переносимо - memmove должен обрабатывать перекрывающиеся области памяти.

...