我用gcc -std=gnu17 -Wall -Werror -Wshadow -O3 test.c
:收到此警告
In function ‘insertString’,
inlined from ‘replaceString’ at test.c:94:5,
inlined from ‘main’ at test.c:110:22:
test.c:69:5: error: ‘strncat’ output may be truncated copying between 0 and 77 bytes from a string of length 80 [-Werror=stringop-truncation]
strncat(source, buffer, STRING_SIZE - 1 - position - strlen(stringToInsert));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
从main()
中删除do while
循环(不对有问题的strncat((语句进行任何更改(会使警告消失。
- 警告是什么意思,为什么会消失
- 我应该在代码中包含哪些更改,以便上面的gcc命令不会触发警告解决方案不能简单地禁用警告(使用fe.#pragma语句(解决方案必须使用strncat((函数
不重要:这是为了学习,请说明。该程序解决了本书第9章中的练习9;"用C编程(第4版(";作者:Stephen G.Kochan
代码:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define STRING_SIZE 81
int findString(const char strToSearch[], const char strSought[])
{
int strToSearchLength = strlen(strToSearch);
int strSoughtLength = strlen(strSought);
for (int i = 0; i <= strToSearchLength - 1; ++i)
{
if (strToSearch[i] == strSought[0])
{
int j = 0;
while (strToSearch[i+j] == strSought[j])
{
if (strSought[j+1] == ' ')
{
return i;
}
++j;
}
}
else if (i > strToSearchLength - strSoughtLength - 1)
{
return -1;
}
}
return -1;
}
bool removeString(char source[], const int start, const int nCharsToRemove)
{
int i, sourceLength = strlen(source);
if (start + nCharsToRemove > sourceLength || start < 0 || nCharsToRemove < 0)
{
printf("Error in function removeString(): invalid parameters.n");
return false;
}
else
{
for (i = start; i < sourceLength; ++i)
{
source[i] = source[i + nCharsToRemove];
}
source[i] = ' ';
return true;
}
}
void insertString(char source[], const char stringToInsert[], const int position)
{
char buffer[STRING_SIZE];
int i = 0;
while (source[position + i] != ' ' && position + i < STRING_SIZE - 1)
{
buffer[i] = source[position + i];
++i;
}
buffer[i] = ' ';
source[position] = ' ';
strncat(source, stringToInsert, STRING_SIZE - 1 - position);
// THE STATEMENT MENTIONED IN THE WARNING:
strncat(source, buffer, STRING_SIZE - 1 - position - strlen(stringToInsert));
}
/* A function to replace the first occurence of the string s1
* inside the source string, if it exists, with the string s2
*/
bool replaceString(char source[], const char s1[], const char s2[])
{
int findString(const char strToSearch[], const char strSought[]);
bool removeString(char source[], const int start, const int nCharsToRemove);
void insertString(char source[], const char stringToInsert[], const int position);
int s1_position;
bool success;
// locate s1 inside source
s1_position = findString(source, s1);
if (s1_position == -1)
return false;
// remove s1 from source
success = removeString(source, s1_position, strlen(s1));
if (! success)
return false;
// insert s2 into source at the proper location
insertString(source, s2, s1_position);
return true;
}
int main(void)
{
char text[STRING_SIZE] = "1 is first*";
// uncommenting the following comment and discarding what follows it makes the warning go away
/*
replaceString(text, "is", "one");
printf("%sn", text);
*/
bool stillFound;
do
stillFound = replaceString(text, "is", "one");
while (stillFound);
printf("%sn", text);
return 0;
}
警告意味着什么
有可能,buffer
将指向一个包含80个字符的字符串,但长度STRING_SIZE - 1 - position - strlen(stringToInsert)
将低于80。创建该警告是为了检测而不是整个源缓冲区将被复制到目标的情况(即在strcat(destination, source)
调用中(。它可能潜在地发生。在这种情况下,目的地缓冲器也不会被零终止。
为什么它会消失?
不同的代码使编译器做出不同的决定。在这种情况下,编译器不会内联调用,这很可能会影响编译器所做的一些静态分析。将static
或attribute((always_inline))
添加到函数将恢复警告。很难回答";为什么";确切地说——答案要么过于宽泛,要么过于详细。我相信检查gcc源或RTL输出可以了解更多信息。
我应该在代码中包含哪些更改,以便上面的gcc命令不会触发警告?
不要使用strncat
。使用memcpy
。我认为:
char *dest = &source[position]; // where we copy to
size_t destfree = STRING_SIZE - 1 - position; // how much space we have there
// helper macro
#define MIN(a, b) ((a)<(b)?(a):(b))
size_t to_copy = MIN(strlen(stringToInsert), destfree);
memcpy(dest, stringToInsert, to_copy);
dest += to_copy;
destfree -= to_copy;
to_copy = MIN(strlen(buffer), destfree);
memcpy(dest, buffer, to_copy);
dest += to_copy;
destfree -= to_copy;
dest[0] = ' ';