C++ 处理字符缓冲区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3113178/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dealing with char buffers
提问by StackedCrooked
As a C++ programmer I sometimes need deal with memory buffers using techniques from C. For example:
作为 C++ 程序员,我有时需要使用来自 C 的技术处理内存缓冲区。例如:
char buffer[512];
sprintf(buffer, "Hello %s!", userName.c_str());
Or in Windows:
或者在 Windows 中:
TCHAR buffer[MAX_PATH+1]; // edit: +1 added
::GetCurrentDirectory(sizeof(buffer)/sizeof(TCHAR), &buffer[0]);
The above sample is how I usually create local buffers (a local stack-allocated char array). However, there are many possible variations and so I'm very interested in your answers to the following questions:
上面的示例是我通常如何创建本地缓冲区(本地堆栈分配的字符数组)。但是,有许多可能的变化,因此我对您对以下问题的回答非常感兴趣:
- Is passing the buffer as
&buffer[0]
better programming style than passingbuffer
? (I prefer&buffer[0]
.) - Is there a maximum size that is considered safe for stack allocated buffers?
- Update:I mean, for example, the highest value that can be considered safe for cross-platform desktop applications on Mac, Windows, Linux desktops (not mobile!).
- Is a static buffer (
static char buffer[N];
) faster? Are there any other arguments for or against it? - When using static buffers you can use return type
const char *
. Is this (generally) a good or a bad idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.) - What about using
static char * buffer = new char[N];
, never deleting the buffer and reusing it on each call. - I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
- Should you prefer the
sprintf_s
,memcpy_s
, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
- 传递缓冲区是否
&buffer[0]
比传递更好的编程风格buffer
?(我更喜欢&buffer[0]
。) - 对于堆栈分配的缓冲区,是否存在被认为安全的最大大小?
- 更新:我的意思是,例如,对于 Mac、Windows、Linux 桌面(不是移动设备!)上的跨平台桌面应用程序可以被认为是安全的最高值。
- 静态缓冲区 (
static char buffer[N];
) 是否更快?是否还有其他支持或反对的论据? - 使用静态缓冲区时,您可以使用 return type
const char *
。这(通常)是一个好主意还是一个坏主意?(我确实意识到调用者需要制作自己的副本,以避免下一次调用会更改先前的返回值。) - 怎么样 using
static char * buffer = new char[N];
,从不删除缓冲区并在每次调用时重用它。 - 我知道在编译时 (1) 处理大缓冲区或 (2) 最大缓冲区大小未知时,应使用堆分配。在堆栈/堆分配决策中还有其他因素吗?
- 您应该更喜欢
sprintf_s
,memcpy_s
, ... 变体吗?(长期以来,Visual Studio 一直试图让我相信这一点,但我想要第二个意见:p)
采纳答案by stinky472
I assume your interest comes about primarily from a performance perspective, since solutions like vector, string, wstring, etc. will generally work even for interacting with C APIs. I recommend learning how to use those and how to use them efficiently. If you really need it, you can even write your own memory allocator to make them super fast. If you are sure they're not what you need, there's still no excuse for you to not write a simple wrapper to handle these string buffers with RAII for the dynamic cases.
我认为您的兴趣主要来自性能角度,因为像 vector、string、wstring 等解决方案通常甚至可以用于与 C API 交互。我建议学习如何使用它们以及如何有效地使用它们。如果你真的需要它,你甚至可以编写自己的内存分配器,让它们变得超快。如果您确定它们不是您所需要的,那么您仍然没有理由不编写一个简单的包装器来使用 RAII 处理动态情况下的这些字符串缓冲区。
With that out of the way:
顺便说一句:
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
将缓冲区作为 &buffer[0] 传递是否比传递缓冲区更好的编程风格?(我更喜欢 &buffer[0]。)
No. I would consider this style to be slightly less useful (admittedly being subjective here) as you cannot use it to pass a null buffer and therefore would have to make exceptions to your style to pass pointers to arrays that can be null. It is required if you pass in data from std::vector to a C API expecting a pointer, however.
不。我会认为这种样式的用处稍低(这里无可否认是主观的),因为您不能使用它来传递空缓冲区,因此必须对您的样式进行例外处理,以将指针传递给可以为空的数组。但是,如果您将数据从 std::vector 传递到需要指针的 C API,则它是必需的。
Is there a maximum size that is considered safe for stack allocated buffers?
对于堆栈分配的缓冲区,是否存在被认为安全的最大大小?
This depends on your platform and compiler settings. Simple rule of thumb: if you're in doubt about whether your code will overflow the stack, write it in a way which can't.
这取决于您的平台和编译器设置。简单的经验法则:如果您不确定您的代码是否会溢出堆栈,请以不会溢出的方式编写它。
Is a static buffer (static char buffer[N];) faster? Are there any other arguments for or against it?
静态缓冲区 (static char buffer[N];) 是否更快?是否还有其他支持或反对的论据?
Yes, there is a big argument against it, and that is that it makes your function no longer re-entrant. If your application becomes multithreaded, these functions will not be thread safe. Even in a single-threaded application, sharing the same buffer when these functions are recursively called can lead to problems.
是的,有一个很大的反对意见,那就是它使您的函数不再可重入。如果您的应用程序变为多线程,则这些函数将不是线程安全的。即使在单线程应用程序中,在递归调用这些函数时共享相同的缓冲区也会导致问题。
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
如何使用 static char * buffer = new char[N]; 并且从不删除缓冲区?(每次调用都重用相同的缓冲区。)
We still have the same problems with re-entrancy.
我们在重入方面仍然存在同样的问题。
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
我知道在编译时 (1) 处理大缓冲区或 (2) 最大缓冲区大小未知时,应使用堆分配。在堆栈/堆分配决策中还有其他因素吗?
Stack unwinding destroys objects on the stack. This is especially important for exception-safety. Thus even if you allocate memory on the heap within a function, it should generally be managed by an object on the stack (ex: smart pointer). ///@see RAII.
堆栈展开会破坏堆栈上的对象。这对于异常安全尤其重要。因此,即使您在函数内的堆上分配内存,它通常也应该由堆栈上的对象管理(例如:智能指针)。///@见RAII。
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
您是否更喜欢 sprintf_s、memcpy_s、... 变体?(长期以来,Visual Studio 一直试图让我相信这一点,但我想要第二个意见:p)
MS was right about these functions being safer alternatives since they don't have buffer overflow problems, but if you write such code just as is (without writing variants for other platforms), your code will be married to Microsoft since it will be non-portable.
MS 认为这些函数是更安全的替代方案是正确的,因为它们没有缓冲区溢出问题,但是如果您按原样编写此类代码(而不为其他平台编写变体),您的代码将与 Microsoft 结合,因为它不会-便携的。
When using static buffers you can use return type const char *. Is this (generally) a good or a bad idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
使用静态缓冲区时,您可以使用返回类型 const char *。这(通常)是一个好主意还是一个坏主意?(我确实意识到调用者需要制作自己的副本,以避免下一次调用会更改先前的返回值。)
I'd say in almost every case, you want to use const char* for return types for a function returning a pointer to a character buffer. For a function to return a mutable char* is generally confusing and problematic. Either it's returning an address to global/static data which it shouldn't be using in the first place (see re-entrancy above), local data of a class (if it's a method) in which case returning it ruins the class's ability to maintain invariants by allowing clients to tamper with it however they like (ex: stored string must always be valid), or returning memory that was specified by a pointer passed in to the function (the only case where one might reasonably argue that mutable char* should be returned).
我会说几乎在所有情况下,您都希望使用 const char* 作为返回指向字符缓冲区的指针的函数的返回类型。对于返回可变 char* 的函数通常是令人困惑和有问题的。要么它返回一个地址给它不应该首先使用的全局/静态数据(参见上面的重入),一个类的本地数据(如果它是一个方法)在这种情况下返回它破坏了类的能力通过允许客户端随意篡改它来维护不变量(例如:存储的字符串必须始终有效),或者返回由传递给函数的指针指定的内存(唯一一种可能合理争辩可变 char* 的情况)应该退回)。
回答by Amardeep AC9MF
Stay away from static buffers if you ever want to use your code re-entrantly.
use snprintf() instead of sprintf() so you can control buffer overruns.
You never know how much stack space is left in the context of your call -- so no size is technically 'safe'. You have a lot of headroom to play with most of the time. But that one time will get you good. I use a rule of thumb to never put arrays on the stack.
Have the client own the buffer and pass it and its size to your function. That makes it re-entrant and leaves no ambiguity as to who needs to manage the life of the buffer.
If you're dealing with string data, double check your string functions to make sure they terminate especially when they hit the end of the buffer. The C library is very inconsistent when it comes to handling string termination across the various functions.
如果您想以可重入方式使用代码,请远离静态缓冲区。
使用 snprintf() 而不是 sprintf() 以便您可以控制缓冲区溢出。
您永远不知道在您的调用上下文中还剩下多少堆栈空间——因此从技术上讲,没有任何大小是“安全的”。大多数时候你有很大的空间可以玩。但那一次会让你好起来。我使用经验法则永远不要将数组放在堆栈上。
让客户端拥有缓冲区并将其及其大小传递给您的函数。这使得它可重入并且对于谁需要管理缓冲区的生命周期没有歧义。
如果您正在处理字符串数据,请仔细检查您的字符串函数以确保它们终止,尤其是当它们到达缓冲区末尾时。在处理跨各种函数的字符串终止时,C 库非常不一致。
回答by GManNickG
- It's up to you, just doing
buffer
is more terse but if it were avector
, you'd need to do&buffer[0]
anyway. - Depends on your intended platform.
- Does it matter? Have you determined it to be a problem? Write the code that's easiest to read and maintain before you go off worrying if you can obfuscate it into something faster. But for what it's worth, allocation on the stack is very fast (you just change the stack pointer value.)
- You should be using
std::string
. If performance becomes a problem, you'd be able to reduce dynamic allocations by just returning the internal buffer. But thestd::string
return interface is way nicer and safer, and performance is your last concern. - That's a memory leak. Many will argue that's okay, since the OS free's it anyway, but I feel it terrible practice to just leak things. Use a static
std::vector
, you should neverbe doing any raw allocation! If you're putting yourself into a position where you might leak (because it needs to be done explicitly), you're doing it wrong. - I think your (1) and (2) just about cover it. Dynamic allocation is almost always slower than stack allocation, but you should be more concerned about which makes sense in your situation.
- You shouldn't be using those at all. Use
std::string
,std::stringstream
,std::copy
, etc.
- 这取决于你,只是做
buffer
更简洁,但如果是vector
,你&buffer[0]
无论如何都需要做。 - 取决于您打算使用的平台。
- 有关系吗?你确定这是一个问题吗?在担心是否可以更快地将其混淆之前,先编写最易于阅读和维护的代码。但就其价值而言,堆栈上的分配非常快(您只需更改堆栈指针值。)
- 你应该使用
std::string
. 如果性能成为问题,您可以通过返回内部缓冲区来减少动态分配。但是std::string
返回接口更好更安全,性能是你最后关心的问题。 - 那是内存泄漏。许多人会争辩说这没关系,因为无论如何操作系统都是免费的,但我觉得泄露东西是一种可怕的做法。使用 static
std::vector
,你不应该做任何原始分配!如果您将自己置于可能会泄漏的位置(因为它需要明确地完成),那么您就做错了。 - 我认为您的 (1) 和 (2) 几乎涵盖了它。动态分配几乎总是比堆栈分配慢,但您应该更关心哪个在您的情况下有意义。
- 你根本不应该使用这些。使用
std::string
,std::stringstream
,std::copy
,等。
回答by Justin Ardini
You have a lot of questions! I'll do my best to answer a couple and give you a place to look for the others.
你有很多问题!我会尽力回答一对夫妇,并给你一个地方去寻找其他人。
Is there a maximum size that is considered safe for stack allocated buffers?
对于堆栈分配的缓冲区,是否存在被认为安全的最大大小?
Yes, but the stack size itself varies based on the platform you are working on. See When do you worry about stack size?for a very similar question.
是的,但堆栈大小本身因您所使用的平台而异。请参阅您何时担心堆栈大小?对于一个非常相似的问题。
Is static char buffer[N]; faster? Are there any other arguments for or against it?
是静态字符缓冲区[N]; 快点?是否还有其他支持或反对的论据?
The meaning of static is dependent on where the buffer is declared, but I assume you are talking about a static
declared inside a function, so it is initialized only once. In functions called many times, using static buffers may be a good idea to prevent stack overflow, but otherwise, keep in mind that allocating buffers is a cheap operation. Also, static buffers are much harder to work with when dealing with multiple threads.
static 的含义取决于声明缓冲区的位置,但我假设您正在谈论static
函数内部的声明,因此它仅被初始化一次。在多次调用的函数中,使用静态缓冲区可能是防止堆栈溢出的好主意,但除此之外,请记住分配缓冲区是一种廉价的操作。此外,在处理多个线程时,静态缓冲区更难使用。
For answers to most of your other questions, see Large buffers vs Large static buffers, is there an advantage?.
有关大多数其他问题的答案,请参阅大缓冲区与大静态缓冲区,是否有优势?.
回答by bta
1) buffer
and &buffer[0]
should be equivalent.
1)buffer
并且&buffer[0]
应该是等价的。
2) Stack size limits will depend on your platform. For most simple functions, my personal rule of thumb is anything over ~256KB is declared dynamically; there's no real rhyme or reason to that number, though, it's just my own convention and it's currently within the default stack sizes for all of the platforms I develop for.
2) 堆栈大小限制取决于您的平台。对于大多数简单的函数,我个人的经验法则是动态声明超过 256KB 的任何内容;这个数字没有真正的韵律或理由,不过,这只是我自己的约定,目前在我开发的所有平台的默认堆栈大小内。
3) Static buffers aren't faster or slower (for all intents and purposes). The only difference is the access control mechanism. The compiler generally places static data in a separate section of the binary file than non-static data, but there is no noticeable/significant performance benefit or penalty involved. The only real way to tell for sure is to write the program both ways and time them (since many of the speed aspects involved here are dependent on your platform/compiler).
3)静态缓冲区不会更快或更慢(出于所有意图和目的)。唯一的区别是访问控制机制。编译器通常将静态数据放在二进制文件的单独部分而不是非静态数据,但不涉及明显/显着的性能优势或损失。唯一真正确定的方法是同时编写程序并为它们计时(因为这里涉及的许多速度方面都取决于您的平台/编译器)。
4) Don't return a const
pointer if the caller will need to modify it (that defeats the point of const
). Use const
for function parameters and return types if and only if they are not designed to be modified. If the caller will need to modify the value, your best bet is for the caller to pass the function a pointer to a pre-allocated buffer (along with the buffer size) and for the function to write the data into that buffer.
4)const
如果调用者需要修改指针(这会破坏 的点),则不要返回指针const
。使用const
函数参数和返回类型,当且仅当它们不是设计进行修改。如果调用者需要修改该值,最好的办法是让调用者向函数传递一个指向预分配缓冲区的指针(以及缓冲区大小),并让函数将数据写入该缓冲区。
5) Reusing a buffer may lead to a performance improvement for larger buffers due to bypassing the overhead that is involved in calling malloc
/free
or new
/delete
each time. However, you run the risk of accidentally using old data if you forget to clear the buffer each time or you try to run two copies of the function in parallel. Again, the only real way to know for sure is to try both ways and measure how long the code takes to run.
5) 由于绕过每次调用malloc
/free
或new
/所涉及的开销,因此重用缓冲区可能会导致较大缓冲区的性能改进delete
。但是,如果您每次忘记清除缓冲区或尝试并行运行该函数的两个副本,您就会冒着意外使用旧数据的风险。同样,唯一真正确定的方法是尝试两种方法并测量代码运行所需的时间。
6) Another factor in stack/heap allocation is scoping. A stack variable goes out of scope when the function it lives in returns, but a variable that was dynamically allocated on the heap can be returned to the caller safely or accessed the next time the function is called (a la strtok).
6) 堆栈/堆分配的另一个因素是范围。当它所在的函数返回时,堆栈变量超出范围,但在堆上动态分配的变量可以安全地返回给调用者或在下次调用函数时访问(la strtok)。
7) I would recommend against the use of sprintf_s
, memcpy_s
, and friends. They are not part of the standard library and are not portable. The more you use these functions, the more extra work you will have when you want to run your code on a different platform or use a different compiler.
7)我会建议不要使用sprintf_s
,memcpy_s
和朋友。它们不是标准库的一部分,不可移植。您使用这些函数的次数越多,当您想在不同的平台上运行代码或使用不同的编译器时,您需要做的额外工作就越多。
回答by Josh Kelley
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
将缓冲区作为 &buffer[0] 传递是否比传递缓冲区更好的编程风格?(我更喜欢 &buffer[0]。)
&buffer[0]
makes the code less readable to me. I have to pause for a second and wonder why someone used it instead of just passing buffer
. Sometimes you have to use &buffer[0]
(if buffer
is a std::vector
), but otherwise, stick with the standard C style.
&buffer[0]
使代码对我来说不太可读。我不得不暂停一秒钟,想知道为什么有人使用它而不是仅仅通过buffer
。有时您必须使用&buffer[0]
(if buffer
is a std::vector
),否则,请坚持使用标准的 C 风格。
Is there a maximum size that is considered safe for stack allocated buffers?
对于堆栈分配的缓冲区,是否存在被认为安全的最大大小?
I doubt there's any practical limit, as long as you're using the stack reasonably. I've never had any problems in my development.
我怀疑是否存在任何实际限制,只要您合理使用堆栈即可。我的开发过程中从来没有遇到过任何问题。
If I'm reading MSDNcorrectly, threads on Windows default to 1MB of stack size. This is configurable. Other platforms have other limits.
如果我正确阅读MSDN,Windows 上的线程默认为 1MB 的堆栈大小。这是可配置的。其他平台有其他限制。
Is static char buffer[N]; faster? Are there any other arguments for or against it?
是静态字符缓冲区[N]; 快点?是否还有其他支持或反对的论据?
On the one hand, it might reduce the need to commit memory pages for stack, so your app might run faster. On the other hand, going to the BSS segmentor equivalent might reduce cache locality compared to the stack, so your app might run slower. I seriously doubt you'd notice the difference either way.
一方面,它可能会减少为堆栈提交内存页面的需要,因此您的应用程序可能会运行得更快。另一方面,与堆栈相比,转到BSS 段或等效段可能会降低缓存局部性,因此您的应用程序可能会运行得更慢。我严重怀疑你会注意到这两种方式的区别。
Using static
is not threadsafe, while using the stack is. That's a huge advantage to the stack. (Even if you don't think you'll be multithreaded, why make life harder if that changes in the future?)
使用static
不是线程安全的,而使用堆栈是。这对堆栈来说是一个巨大的优势。(即使您不认为自己会成为多线程,如果将来发生变化,为什么还要让生活变得更艰难?)
When using static buffers you can have your function return have the const char * return type. Is this a good idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
使用静态缓冲区时,您可以让函数返回具有 const char * 返回类型。这是一个好主意吗?(我确实意识到调用者需要制作自己的副本,以避免下一次调用会更改先前的返回值。)
Const correctnessis always a good thing.
Const 正确性总是一件好事。
Returning pointers to static buffers is error-prone; a later call might modify it, another thread might modify it, etc. Use std::string
instead or other auto-allocated memory instead (even if your function needs to deal internally with char buffers such as your GetCurrentDirectory
example.)
返回指向静态缓冲区的指针容易出错;稍后的调用可能会修改它,另一个线程可能会修改它,等等。使用std::string
替代或其他自动分配的内存代替(即使您的函数需要在内部处理字符缓冲区,例如您的GetCurrentDirectory
示例。)
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
如何使用 static char * buffer = new char[N]; 并且从不删除缓冲区?(每次调用都重用相同的缓冲区。)
Less efficient than just using static char buffer[N]
, since you need a heap allocation.
比使用 效率低static char buffer[N]
,因为您需要堆分配。
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
我知道在编译时 (1) 处理大缓冲区或 (2) 最大缓冲区大小未知时,应使用堆分配。在堆栈/堆分配决策中还有其他因素吗?
See Justin Ardini's answer.
请参阅贾斯汀·阿迪尼 (Justin Ardini) 的回答。
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
您是否更喜欢 sprintf_s、memcpy_s、... 变体?(长期以来,Visual Studio 一直试图让我相信这一点,但我想要第二个意见:p)
This is a matter of some debate. Personally, I think these functions are a good idea, and if you're targeting Windows exclusively, then there's some benefit to taking the preferred Windows approach and using those functions. (And they're fairly straightforward to reimplement if you later need to target something other than Windows, as long as you don't rely on their error-handling behavior.) Others think that the Secure CRT functions are no more secure than properly used C and introduce other disadvantages; Wikipedia linksto a few arguments against them.
这是一个有争议的问题。就我个人而言,我认为这些功能是一个好主意,如果您专门针对 Windows,那么采用首选的 Windows 方法并使用这些功能会有一些好处。(如果您以后需要针对 Windows 以外的其他东西,只要您不依赖它们的错误处理行为,重新实现它们就相当简单。)其他人认为安全 CRT 功能并不比正确使用更安全C 并引入其他缺点;维基百科链接到一些反对他们的论点。
回答by Mark Ransom
If a function gives you a method of knowing how many characters it will return, use it. Your sample GetCurrentDirectory is a good example:
如果一个函数为您提供了一种知道它将返回多少个字符的方法,请使用它。您的示例 GetCurrentDirectory 就是一个很好的例子:
DWORD length = ::GetCurrentDirectory(0, NULL);
Then you can use a dynamically allocated array (either string or vector) to get the result:
然后您可以使用动态分配的数组(字符串或向量)来获得结果:
std::vector<TCHAR> buffer(length, 0);
// assert(buffer.capacity() >= length); // should always be true
GetCurrentDirectory(length, &buffer[0]);
回答by INS
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
Is passing the buffer as &buffer[0] better programming style than passing buffer? (I prefer &buffer[0].)
It depends on the coding standards. I personally prefer: buffer + index
instead of &buffer[index]
but it's a matter of taste.
这取决于编码标准。我个人更喜欢:buffer + index
而不是&buffer[index]
但这是一个品味问题。
Is there a maximum size that is considered safe for stack allocated buffers?
Is there a maximum size that is considered safe for stack allocated buffers?
It depends on the stack size. If the amount of stack needed for your buffer exceeds the amount available on the stack, it result a stack-overflow.
这取决于堆栈大小。如果缓冲区所需的堆栈量超过堆栈上可用的数量,则会导致stack-overflow。
Is static char buffer[N]; faster? Are there any other arguments for or against it?
Is static char buffer[N]; faster? Are there any other arguments for or against it?
Yes, it should be faster. See also this question: Is it bad practice to declare an array mid-function
是的,它应该更快。另请参阅此问题:声明数组中间函数是不好的做法
When using static buffers you can have your function return have the const char * return type. Is this a good idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
When using static buffers you can have your function return have the const char * return type. Is this a good idea? (I do realize that the caller will need to make his own copy to avoid that the next call would change the previous return value.)
Not sure what static means in this case but:
不确定在这种情况下静态意味着什么,但是:
If variable is declared on stack(
char buf[100]
): You should notreturn references to stuff that is declared on the stack. They will be trashed at next function call/declaration (e.g. when the stack is used again).If the variable is declared as static
static
it will make your code non-reentrant. strtokis an example in this case.
如果这个变量在堆栈上宣布(
char buf[100]
):你应该不会返回在堆栈上宣布的东西引用。它们将在下一次函数调用/声明时被丢弃(例如,当再次使用堆栈时)。如果变量被声明为静态的,
static
它将使您的代码不可重入。strtok就是这种情况下的一个例子。
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
What about using static char * buffer = new char[N]; and never deleting the buffer? (Reusing the same buffer each call.)
It is a possibility, though not recommended because it makes your code non-reentrant.
这是一种可能性,但不推荐,因为它使您的代码不可重入。
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
I understand that heap allocation should be used when (1) dealing with large buffers or (2) maximum buffer size is unknown at compile time. Are there any other factors that play in the stack/heap allocation decision?
Stack size of the running thread is too small to fit stack declaration (previously mentioned).
正在运行的线程的堆栈大小太小,无法容纳堆栈声明(前面提到过)。
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
Should you prefer the sprintf_s, memcpy_s, ... variants? (Visual Studio has been trying to convince me of this for a long time, but I want a second opinion :p )
If you want your code to be portable: No. But the effort in creating a portable macro is quite small in this case:
如果你希望你的代码是可移植的:不。但在这种情况下,创建可移植宏的工作量很小:
// this is not tested - it is just an example
#ifdef _WINDOWS
#define SPRINTF sprintf_s
#else
#define SPRINTF sprintf
#endif
回答by Patrick
- Buffer or &Buffer[0] is exactly the same. You could even write Buffer+0. Personally I prefer just to write Buffer (and I think most developers also prefer this), but this is your personal choice
- The maximum depends on how big and how deep your stack is. If you are already 100 functions deep in the stack, the maximum size will be smaller. If you can use C++, you could write a buffer class that dynamically chooses whether to use the stack (for small sizes) or the heap (for large sizes). You will find the code below.
- A static buffer is faster since the compiler will reserve the space for you beforehand. A stack buffer is also fast. For a stack buffer the application just has to increase the stack pointer. For a heap buffer, the memory manager has to find free space, ask the operating system for new memory, afterwards free it again, do some bookkeeping, ...
- If possible use C++ strings to avoid memory leaks. Otherwise, the caller has to know whether he has to free the memory afterwards or not. The downside is that C++ strings are slower than static buffers (since they are allocated on the heap).
- I wouldn't use memory allocation on global variables. When are you going to delete it? And can you be sure that no other global variable will need the allocated memory (and be used before your static buffer is allocated)?
- Whatever kind of buffer you use, try to hide the implementation from the caller of your function. You could try to hide the buffer-pointer in a class let the class remember whether the buffer is dynamically allocated or not (and thus should delete it in its destructor or not). Afterwards it's easy to change the type of the buffer, which you can't do if you just return a char-pointer.
- Personally I prefer the normal sprintf variants, but that's probably because I still have lots of older code and I don't want a mixed situation. In any case, consider using snprintf, where you can pass the buffer size.
- Buffer 或 &Buffer[0] 完全一样。你甚至可以写 Buffer+0。我个人更喜欢只写 Buffer(我认为大多数开发人员也喜欢这个),但这是你个人的选择
- 最大值取决于您的筹码量有多大和有多深。如果堆栈中已经有 100 个函数,则最大大小会更小。如果您可以使用 C++,您可以编写一个缓冲区类来动态选择是使用堆栈(对于小尺寸)还是堆(对于大尺寸)。您将在下面找到代码。
- 静态缓冲区更快,因为编译器会事先为您保留空间。堆栈缓冲区也很快。对于堆栈缓冲区,应用程序只需要增加堆栈指针。对于堆缓冲区,内存管理器必须找到可用空间,向操作系统请求新内存,然后再次释放它,做一些簿记,......
- 如果可能,请使用 C++ 字符串以避免内存泄漏。否则,调用者必须知道他之后是否必须释放内存。缺点是 C++ 字符串比静态缓冲区慢(因为它们是在堆上分配的)。
- 我不会在全局变量上使用内存分配。你打算什么时候删除它?您能否确定没有其他全局变量需要分配的内存(并在分配静态缓冲区之前使用)?
- 无论您使用哪种缓冲区,都应尝试对函数调用者隐藏实现。您可以尝试在类中隐藏缓冲区指针,让类记住缓冲区是否是动态分配的(因此应该在其析构函数中删除它)。之后很容易改变缓冲区的类型,如果你只返回一个字符指针,你就不能这样做。
- 就我个人而言,我更喜欢普通的 sprintf 变体,但这可能是因为我仍然有很多旧代码,而且我不希望出现混合情况。在任何情况下,请考虑使用 snprintf,您可以在其中传递缓冲区大小。
Code for dynamic stack/heap buffer:
动态堆栈/堆缓冲区的代码:
template<size_t BUFSIZE,typename eltType=char>
class DynamicBuffer
{
private:
const static size_t MAXSIZE=1000;
public:
DynamicBuffer() : m_pointer(0) {if (BUFSIZE>=MAXSIZE) m_pointer = new eltType[BUFSIZE];}
~DynamicBuffer() {if (BUFSIZE>=MAXSIZE) delete[] m_pointer;};
operator eltType * () { return BUFSIZE>=MAXSIZE ? m_pointer : m_buffer; }
operator const eltType * () const { return BUFSIZE>=MAXSIZE ? m_pointer : m_buffer; }
private:
eltType m_buffer[BUFSIZE<MAXSIZE?BUFSIZE:1];
eltType *m_pointer;
};