我正在学习C.我有一个方法,需要3个字符串并将它们组合起来做一些操作。以下是我使用GCC编译器的第一个实现。
void foo(const char *p1, const char *p2, const char *p3)
{
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char combined[length + 1];
memset(combined, 0, length + 1);
strcat(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
}
int main()
{
foo("hello ", "world ", "how");
return 0;
}
这很有效。但是当我使用cc -Wall -pedantic -g foo.c -o foo
编译时,我开始收到像ISO C90 forbids variable length array ‘combined’
这样的警告。 MSVC没有编译此代码。改变了像
void foo(const char *p1, const char *p2, const char *p3)
{
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char *combined = (char *) malloc(length + 1);
memset(combined, 0, length + 1);
strcat(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
free(combined);
}
问题
-Wall -pedantic
。我也应该使用-ansi
吗? MSVC中可用的等效标志是什么?答案 0 :(得分:8)
这很有效。但是当我使用cc -Wall -pedantic -g foo.c -o foo编译它时,我开始收到像ISO C90这样的警告,禁止变量长度数组“组合”。
尝试使用-std=c99
选项(gcc)进行编译。
MSVC没有编译此代码。改变了像
这样的代码如果可变长度数组不是标准的一部分,为什么GCC实现它呢?
VLA是ISO C99(gcc和g ++(作为扩展)支持VLA)的一部分。 MSVC仍然只支持C89。
我的代码预计将在GCC和MSVC上编译。
然后你不应该在代码恕我直言中使用VLA。
答案 1 :(得分:7)
memset
是浪费时间,但是因为它会被覆盖(将你的第一个strcat
变成strcpy
)。你应该总是检查malloc
返回NULL。 无论如何! malloc
是您最好的选择,特别是如果您想返回组合字符串。-std=c89
标志或类似的东西。无论如何,MSVC并不总是遵循标准: - )我会选择:
void foo (const char *p1, const char *p2, const char *p3) {
size_t length = strlen(p1) + strlen(p2) + strlen(p3);
char *combined = (char *) malloc(length + 1);
if (combined == NULL) {
printf("Result : <unknown since I could't get any memory>\n");
} else {
strcpy(combined, p1);
strcat(combined, p2);
strcat(combined, p3);
printf("Result : %s", combined);
free(combined);
}
}
或者,因为除了打印它之外你实际上没有对字符串做任何事情:
void foo (const char *p1, const char *p2, const char *p3) {
printf("Result : %s%s%s", p1, p2, p3);
}
: - )
我见过的另一个策略是“只有你必须分配”战略:
void foo (const char *p1, const char *p2, const char *p3) {
char str1k[1024];
char *combined;
size_t length = strlen (p1) + strlen (p2) + strlen (p3) + 1;
if (length <= sizeof(str1k))
combined = str1k;
else
combined = malloc (length);
if (combined == NULL) {
printf ("Result : <unknown since I couldn't get any memory>\n");
} else {
strcpy (combined, p1);
strcat (combined, p2);
strcat (combined, p3);
printf ("Result : %s", combined);
}
if (combined != str1k)
free (combined);
}
如果组合的字符串适合,则使用堆栈存储,如果不适合则仅分配内存。如果大量字符串合并到小于限制范围内,这通常可以显着提高速度。
答案 2 :(得分:3)
可变长度数组不是第一个ISO C标准(不同地称为“C89”,“C90”或“ANSI C”)的一部分。但是,它们 是最新ISO C标准的一部分(称为“C99”)。
GCC可以用几种模式编译你的代码,包括“严格的C90”,“C90-with-GNU-C-extensions”和“C99”(虽然它没有完全实现C99,它足够接近大多数实际用途。)
默认情况下,GCC使用“C90-with-GNU-C-extensions”,这就是为什么您的代码无需投诉即可编译的原因。使用-pedantic
告诉它按相关标准(在本例中为C90)发出所有必需的警告,并且您的代码需要这样的警告。如果你给GCC -std=c99 -pedantic
标志,告诉它根据C99基本标准进行编译并发出所有必需的警告,你的代码编译得很好。
如果您想确保您的代码与基本C90标准兼容,那么在编译C时使用-std=c90 -pedantic
(或-ansi -pedantic
:-ansi
是-std=c90
的同义词码)。请注意,MSVC不支持C99。
答案 3 :(得分:0)
解决这些问题的一个非常常见的习惯是让调用者管理内存。因此,不是自己分配内存(使用堆栈上的可变长度数组或通过malloc
某些东西,或其他任何东西),而是期望调用者提供内存。考虑一下:
int foo(const char *p1, const char *p2, const char *p3, char *buf, size_t bufsize)
{
size_t requiredSize = strlen(p1) + strlen(p2) + strlen(p3) + 1;
if (!buf)
return requiredSize;
if (requiredSize > bufsize)
return -1;
buf[0] = '\0';
strcat(buf, p1);
strcat(buf, p2);
strcat(buf, p3);
return requiredSize;
}
int main()
{
/* simple case: caller knows that the buffer is large enough. */
char buf[ 1024 ];
foo( "Hello", "World", "Bar", buf, sizeof(buf) );
printf("Result : %s\n", buf);
/* complicated case: caller wants to allocate buffer of just the right size */
size_t bufsize = foo( "Hello", "World", "Bar", NULL, 0 );
char *buf2 = (char *)malloc(bufsize);
foo( "Hello", "World", "Bar", buf2, bufsize );
free( buf2 );
}
这种方法的优点是foo
永远不会泄漏。除此之外,调用者可以使用简单的基于堆栈的数组,以防它适用于他。如果他想知道确切的大小,他可以调用foo
并传递NULL
作为第四个参数。