C, sprintf и "сумма" строки и int - PullRequest
0 голосов
/ 08 июля 2010

Я не использовал C в течение длительного времени, и теперь я должен изменить небольшой кусочек кода.Есть одна вещь, которую я не могу понять:

char filename[20];
filename[0] = '\0';
for (j=0; j < SHA_DIGEST_LENGTH; j++){
  sprintf(filename + strlen(filename),"%02x",result[j]);
}

В первой строке указана строка из 20 символов.Во второй строке первый символ установлен в '\ 0', поэтому я полагаю, что это пустая строка.

В цикле for я не понимаю "сумму" между именем файла и его длиной.Параметр firs в sprintf должен быть буфером, куда копировать форматированную строку справа.Каков результат этой суммы?Мне кажется, что я пытаюсь суммировать массив и целое число ...

Чего мне не хватает?

Ответы [ 5 ]

13 голосов
/ 08 июля 2010

Это арифметика указателя. strlen возвращает количество символов перед NUL-терминатором. Результат сложения будет указывать на этот терминатор. Например. если текущей строкой является «AA» (за которым следует NUL), strlen равен 2. filename + 2 указывает на NUL. Он будет записывать следующие шестнадцатеричные символы (например, BB) поверх NUL и следующего символа. Затем он снова завершит NUL (на filename + 4). Так что тогда у вас будет "AABB" (тогда NUL).

Хотя на самом деле это не имеет смысла. Поиск этих NULs тратит много времени. В частности, это квадратичный алгоритм. В первый раз проверяется 1 символ, затем 3, 5, 7, ..., 2 * SHA_DIGEST_LENGTH - 1) это. Это может быть просто:

sprintf(filename + 2 * j,"%02x",result[j]);

Есть еще одна проблема. Шестнадцатеричное представление суммы SHA-1 занимает 40 символов, поскольку байт требует двух символов. Затем у вас есть конечный терминатор NUL, поэтому их должно быть 41. В противном случае переполнение буфера.

1 голос
/ 08 июля 2010

Почему бы вам не объявить

char filename[SHA_DIGEST_LEN*2 +1]; / * И +1, если вы хотите иметь завершающий символ NULL * /

Это потому, что длина дайджеста SHA1 составляет 20 байтов. Если вы просто печатали дайджест, то, возможно, вам не нужна дополнительная память, но, поскольку вы хотите шестнадцатеричную строку дайджеста, вы можете использовать вышеуказанное объявление. Операция strlen возвращает длину строки до тех пор, пока не встретится нулевой завершающий символ.

Так что в основном, когда вы делаете следующее:

sprintf(filename + strlen(filename),"%02x",result[j]);

В первом случае имя файла копируется с 2 байтами шестнадцатеричного представления первого байта дайджеста sha-1. Например. Скажем, это AA, теперь вам нужно переместить указатель на два места, чтобы скопировать следующий байт.

После второй итерации он становится AABB. После 20-й итерации у вас есть вся строка AABBCC ...... AA [40 байт] и +1, если вам нужен '\ 0', который является символом завершения NULL.

1 голос
/ 08 июля 2010

Первая итерация, когда j = 0, вы запишите 3 символа (да, включая '\0', заканчивающий строку) в начало filename, так как затем strlen () возвращает 0. Следующий раунд, strlen ()возвращает 2, и он продолжит запись после первых двух символов.

Будьте осторожны, чтобы выйти за пределы выделенного пространства в 20 символов.Распространенная ошибка - забыть пространство, необходимое для ограничителя строки.

EDIT : убедитесь, что SHA_DIGEST_LENGTH не больше 9.

0 голосов
/ 08 июля 2010

Заменить код на:

char filename[SHA_DIGEST_LENGTH*2+1];
for (j=0; j < SHA_DIGEST_LENGTH; j++){
  sprintf(filename + 2*j,"%02x",result[j]);
}

Быстрее, проще, и ошибки исчезли.

0 голосов
/ 08 июля 2010

вы добавляете strlen (имя файла) только для объединения результатов [j]

Каждая итерация объединяет текущий результат [j] в конце имени файла, поэтому каждый раз, когда вам нужно знать, смещение в имени файла, где должна происходить конкатенация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...