【发布时间】:2010-07-07 08:19:28
【问题描述】:
我正在学习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);
}
问题
- 这是正确的实现吗?
- 如果可变长度数组不是标准的一部分,为什么 GCC 实现它?如果预计代码只能在 GCC 上编译,那么使用变量数组会比使用 malloc 更好吗?
- 我认为经验法则是,如果在编译时知道所需的内存,则使用数组,否则使用 malloc 分配所需的内存。这是正确的吗?
- 我的代码预计可以在 GCC 和 MSVC 上编译。我通常会在 GCC 上进行开发。那么确保最大可移植性的编译器标志是什么?目前我正在使用
-Wall -pedantic。我也应该使用-ansi吗? MSVC 中可用的等效标志是什么? - 编写可移植 C 代码时还需要考虑哪些其他常见事项?
【问题讨论】:
-
(1)是的,正如您在第 3 点中提到的那样 (2)因为 gcc 还支持除 ISO C90 之外的其他标准。 (5)google.com/search?q=writing+portable+C+code动态分配VLA总是比较好,因为你可以查看(m/c)alloc的返回值,看看分配是否成功
-
@itisravi - 您应该回答,而不是在评论中回答。由于评论长度限制,您对 VLA 与动态分配的建议有点稀疏。我同意,我知道你在说什么,但目前还不清楚,因为 cmets 太短了,无法回答。这就是为什么我们有答案。 ;)
-
VLA 太大(取决于平台)也可能导致堆栈溢出。对于您的第二个变体,这看起来是正确的,但我要么使用
calloc进行分配,要么通过分配combined[0] = '\0'来避免memset。这足以让第一个strcat正常工作。 -
不需要转换返回
void *的库函数。只需使用char *combined = malloc(length + 1);。另外,您想检查malloc()的返回。顺便说一句,snprintf()在这种情况下会更好,imo。
标签: c string portability