字符串操作&内存分配-C
我正在学习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 禁止可变长度数组“组合”之类的警告。 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 代码时需要考虑的其他常见事项是什么?
I am in the process of learning C. I have a method that takes 3 strings and combines them to do some operation. Following was my first implementation using a GCC compiler.
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;
}
This works well. But when I compiled this using, cc -Wall -pedantic -g foo.c -o foo
, I started getting warnings like ISO C90 forbids variable length array ‘combined’
. MSVC was not compiling this code. Changed the code like
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);
}
Questions
- Is this the correct implementation?
- If variable length arrays are not part of standard, why GCC implemented it? If the code is expected to compile only on GCC, using variable arrays will be a better alternative than using malloc?
- I think the thumb rule is, if memory required is knows at compile time, use arrays else use malloc to allocate required memory. Is this correct?
- My code is expected to compile on GCC and MSVC. I will be developing on GCC usually. So what are the compiler flags that ensures maximum portability? Currently I am using
-Wall -pedantic
. Should I use-ansi
too? What would be the equivalent flags available in MSVC? - What are the other common things to consider when writing portable C code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
尝试使用 -std=c99 选项 (gcc) 进行编译。
VLA 是 ISO C99 的一部分(gcc 和 g++(作为扩展)支持 VLA)。 MSVC仍然只支持C89。
那么您不应该在代码中使用 VLA(恕我直言)。
Try compiling with
-std=c99
option (gcc).VLAs are part of ISO C99(gcc and g++(as an extension) support VLAs). MSVC still only supports C89.
Then you should not use VLAs in your code IMHO.
strcat
变成strcpy
)。并且您应该始终检查malloc
是否返回NULL。 无论如何!malloc
是您最好的选择,特别是如果您想返回组合字符串。-std=c89
标志或类似的东西。无论如何,MSVC并不总是遵循标准:-)我会选择:
或者,因为除了打印字符串之外,您实际上没有对字符串执行任何操作:
:-)
我看到的另一个策略是“仅在必须时分配”策略:
如果组合,则使用堆栈存储string 将适合,并且仅在不适合的情况下分配内存。如果大量字符串组合起来小于限制,这通常会导致速度的显着提高。
memset
is a waste of time however since it's al going to be overwritten anyway (make your firststrcat
into astrcpy
). And you should always check formalloc
returning NULL. No matter what!malloc
is your best bet, particularly if you want to return the combined string.-std=c89
flag or something similar. In any case, MSVC does not always follow the standard :-)I would opt for:
or, since you're not actually doing anything with the string except printing it:
:-)
Another strategy I've seen is the "only allocate if you have to" strategy:
which uses stack storage if the combined string will fit and only allocates memory if it won't. This can often lead to a substantial speed improvement if the bulk of strings combine into less than the limit.
可变长度数组不是第一个 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 标准兼容,请使用
-std=c90 -pedantic
(或-ansi -pedantic
:-ansi< /code> 是编译 C 代码时
-std=c90
的同义词)。请注意,MSVC 不支持 C99。Variable-length arrays were not part of the first ISO C standard (variously referred to as "C89", "C90" or "ANSI C"). However, they are a part of the latest ISO C standard (known as "C99").
GCC can compile your code in several modes, including "strict C90", "C90-with-GNU-C-extensions", and "C99" (although it does not fully implement C99, it is close enough for most practical purposes).
By default, GCC uses "C90-with-GNU-C-extensions", which is why your code compiles without complaint. Using
-pedantic
tells it to emit all required warnings by the relevant standard (in this case, C90), and such a warning is required by your code. If you give GCC the-std=c99 -pedantic
flags, to tell it to compile against the C99 base standard and emit all required warnings, your code compiles fine.If you want to ensure your code is compatible with the base C90 standard, then use
-std=c90 -pedantic
(or-ansi -pedantic
:-ansi
is a synonym for-std=c90
when compiling C code). Note that MSVC does not support C99.解决这些问题的一个非常常见的习惯是让调用者管理内存。因此,您期望调用者提供内存,而不是自己分配内存(使用堆栈上的可变长度数组或通过 malloc 进行某些操作或其他方式)。考虑一下:
这种方法的优点是
foo
永远不会泄漏。除此之外,调用者还可以使用一个简单的基于堆栈的数组,以防它对他有用。如果他想知道确切的大小,他可以调用foo
并传递NULL
作为第四个参数。A very common idiom to work around these issues is to let the caller manage the memory. So instead of allocating memory yourself (either using a variable-length array on the stack or by
malloc
'ing something, or whatever) you expect the caller to provide memory. Consider this:The advantage of this approach is that
foo
will never leak. In addition to that, the caller can use a simple stack-based array in case it works for him. If he wants to know the exact size he can callfoo
and passNULL
as the fourth argument.