I'm trying to reproduce the behavior of std::string in C, but there is one thing I don't really know how to do. There is a max_size
member method that gives the maximum size a string (or any other arrays for vector, etc...) can have, so my question is I know this value can depend of systems, so how do containers determine this number ? And could I get it in C?
The set::max_size() is a built-in function in C++ STL which returns the maximum number of elements a set container can hold. Syntax: set_name.max_size() Parameters: This function does not accept any parameters. Return Value: This function returns the maximum number of elements a set container can hold.
@BjörnPollex Yes! I forgot to mention that.
max_size() is the theoretical maximum number of items that could be put in your vector. On a 32-bit system, you could in theory allocate 4Gb == 2^32 which is 2^32 char values, 2^30 int values or 2^29 double values.
The set::max_size () is a built-in function in C++ STL which returns the maximum number of elements a set container can hold. Parameters: This function does not accept any parameters. Return Value: This function returns the maximum number of elements a set container can hold. Below program illustrates the above funnction:
Containers in C++ STL (Standard Template Library) Last Updated: 12-07-2020 A container is a holder object that stores a collection of other objects (its elements).
If we use std::max () to find the maximum element in a container for a range, then we have to write our own iterator and comparator. std::max_element () is pretty handy if we would want to find the maximum element value in a subrange.
The size of a container is the number of elements it contains. Or said differently, the number of elements passed over in an iteration from beginning to end. This is an information which is fundamentally part of the container interface.
What determines max_size in STL containers?
The implementer of the standard library chooses it. The implementers should design containers to support as large sizes as possible, given the limitations imposed by the API and the target system. The implementation defails of the container, and the supplied allocator may impose additional limitations that should ideally be reflected by a lowered (and thus more accurate) max_size
.
Note that max_size
is only rarely useful value in practice. It is a theoretical upper bound that is not necessarily practically reachable... typically because memory isn't sufficient, at least on 64 bit systems. It's used to detect obviously erroneus user input early (and then throw exception accordingly).
And could I get it in C?
You can define a constant extern variable and initialise it in a c++ translation unit. Example:
// common_header.h
// add header guard here
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const size_t cpp_string_max_size;
extern const size_t cpp_vector_int_max_size;
#ifdef __cplusplus
}
#endif
// source.cpp
#include "common_header.h"
#include <string>
#include <cstdlib>
#include <vector>
const std::size_t cpp_string_max_size = std::string{}.max_size();
const std::size_t cpp_vector_int_max_size = std::vector<int>{}.max_size();
Then, compile the C++ translation unit using a C++ compiler and link it with the C program.
I'm searching for a way that doesn't involve any C++
Depending on what you mean by "any C++", you can use meta-programming: Write a C++ program that produces a C source file that contains constants that were produced by the C++ program. The generation part obviously involves C++, but the generated source will be pure C and can be compiled using only a C compiler.
If this isn't to your liking, you can go read the implementation files of your chosen C++ standard library and see how they have implemented max_size
, and write the C source manually. This doesn't involve writing or compiling any C++ at any point, although it does involve reading C++.
max_size
defines the maximum size a container theoretically can have for the particular implementation of that container.
That number does not depend on the OS or the available memory but is only given by the implementation of the container.
If your (not std::string
compatible) implementation of a string container is like this:
struct string {
unsigned char size;
char *data;
// … further functions …
};
Then max_size
would likely refer to the largest number unsigned char
can represent.
If your implementation is just a \0
terminated string, without any other meta information. Then max_size
might refer to the maximum number of bytes that can be addressed through pointers, for the given target architecture.
So max_size
just says, the way the container is implemented would be able to handle max_size
number of elements. But it does not guarantee that the OS is capable of that.
For an std::string
the upper bounds of the maximum number of chars the implementation can handle is given by a maximum number of size_type
and some further constraints.
The size_type
for a std::string
itself is given by the used allocator (std::allocator<CharT>
) which defaults to std::allocator_traits<Allocator>::size_type
.
For a std::allocator
the size_type
referees to std::size_t
.
So for a std::string
the upper bound of max_size
is the max value of std::size_t
minus a value n
that is required to fulfill the other requirements of the string.
The libstdc++
of gcc-4.6.2
defines says this about the max_size
:
// The maximum number of individual char_type elements of an
// individual string is determined by _S_max_size. This is the
// value that will be returned by max_size(). (Whereas npos
// is the maximum number of bytes the allocator can allocate.)
// If one was to divvy up the theoretical largest size string,
// with a terminating character and m _CharT elements, it'd
// look like this:
// npos = sizeof(_Rep) + (m * sizeof(_CharT)) + sizeof(_CharT)
// Solving for m:
// m = ((npos - sizeof(_Rep))/sizeof(CharT)) - 1
// In addition, this implementation quarters this amount.
static const size_type _S_max_size;
static const _CharT _S_terminal;
and that corresponding initialization
template<typename _CharT, typename _Traits, typename _Alloc>
const typename basic_string<_CharT, _Traits, _Alloc>::size_type
basic_string<_CharT, _Traits, _Alloc>::
_Rep::_S_max_size = (((npos - sizeof(_Rep_base))/sizeof(_CharT)) - 1) / 4;
According to this 197. max_size() underspecified (not sure if there is any newer update to that), the value of max_size
won't change from call to call:
It is clear to the LWG that the value returned by max_size() can't change from call to call.
So you can use the approach of eerorika to get that value for a specific allocator.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With