Why this MSVC API is defined this way?
errno_t _开发者_StackOverflow中文版dupenv_s(
char **buffer,
size_t *sizeInBytes,
const char *varname
);
I have several questions regarding this:
- why a pointer to pointer(
**
) is required instead of a pointer(*
)? - why
sizeInBytes
is necessary,isn't that available bystrlen(buffer)
?
Any function suffixed with _s
under msvc is a secure function, this means it makes no assumptions about the integrity of the data passed. For this very reason the length of the string is required, because you can't assume its null terminated, or terminated at all (you might also only want half the string, but thats a side effect).
The secure functions all return error codes so that they can be checked without the possibility of faulting, and due to this any returns need to be sent via pointers. And seeing as the non-secure version of strdup
& dupenv
return a char*
, you get a double indirection so that the pointer to the variable you pass gets the address of the allocated buffer.
No, it's asking for the address of a character pointer. The method will allocate the necessary space to hold the variable's value and set the value of your pointer to it, otherwise NULL. Refer to the example code down the page:
http://msdn.microsoft.com/en-us/library/ms175774(v=VS.80).aspx
In this context, the type char**
is a pointer to a pointer to an array of char
s. (It can also mean a pointer to a pointer to a single char
, but that's not how it's used with _dupenv_s()
).
The _dupenv_s()
function allocates an array of char
s by asking the operating system to reserve some chunk of memory big enough to hold it. The operating system reserves a chunk of memory and gives the _dupenv_s()
function the address of this newly-allocated char
array. The _dupenv_s()
function stores the address of this array into a char*
variable, because it's a pointer to an array of char
s.
Now, the function has to pass this char*
value out to the caller so the calling code can use it. The return value is already used to return an error code, so that can't be used. But let's say that the caller has a char*
variable ready to receive the address to the allocated buffer.
If the _dupenv_s()
function knows where the caller's char*
variable is located, then the function can go ahead and fill the caller's char*
variable with the correct value. To do that, the caller needs to pass the address of the caller's char*
variable. That is, you need to pass a pointer to a pointer to an array of chars
. That means a char**
must be passed.
Note that's also the reason why sizeInBytes
is a size_t*
. The caller has a variable size_t
, and the caller can pass the address of the variable to the function as a size_t*
so that the function can fill the variable with the correct value.
While it may be true that strlen(buffer) == sizeInBytes
, the strlen()
function determines the length of the string by counting the number of characters until it sees a null-terminator. The amount of time required for strlen()
to complete is linear to the number of characters, i.e. it's not constant. Why not skip the trouble of requiring the caller to do that and just provide the size directly?
If pointers still confuse you (and they are confusing at times), this Stack Overflow answer can be of assistance.
精彩评论