问题
Following is the most popular implementation of strcpy in traditional systems. Why dest and src are not checked for NULL in the start? I heard once that in old days the memory was limited so short code was always preferred. Will you implement strcpy and other similar functions with NULL pointer checks at the start now days? Why not?
char *strcpy(char *dest, const char *src)
{
char *save = dest;
while(*dest++ = *src++);
return save;
}
回答1:
NULL
is a bad pointer, but so is (char*)0x1
. Should it also check for that? In my opinion (I don't know the definitive reason why), sanity checks in such a low-level operation are uncalled for. strcpy()
is so fundamental that it should be treated something like as asm instruction, and you should do your own sanity checks in the caller if needed. Just my 2 cents :)
回答2:
There are no sanity checks because one of the most important underlying ideologies of C is that the developer supplies the sanity. When you assume that the developer is sane, you end up with a language that can be used to do just about anything, anywhere.
This is not an explicitly stated goal — it's quite possible for someone to come up with an implementation that does check for this, and more. Maybe they have. But I doubt that many people used to C would clamour to use it, since they'd need to put the checks in anyway if there was any chance that their code would be ported to a more usual implementation.
回答3:
The whole C language is written with the motto "We'll behave correctly provided the programmer knows what he's doing." The programmer is expected to know to make all the checks he needs to make. It's not just checking for NULL, it's ensuring that dest
points to enough allocated memory to hold src
, it's checking the return value of fopen
to make sure the file really did open successfully, knowing when memcpy
is safe and when memmove
is required, and so on.
Getting strcpy
to check for NULL won't change the language paradigm. You will still need to ensure that dest
points to enough space -- and this is something that strcpy
can't check for without changing the interface. You will also need to ensure that src
is '\0'
-terminated, which again strcpy
can't possibly check.
There are some C standard library functions which do check for NULL: for example, free(NULL)
is always safe. But in general, C expects you to know what you're doing.
[C++ generally eschews the <cstring>
library in favour of std::string
and friends.]
回答4:
It's usually better for the library to let the caller decide what it wants the failure semantics to be. What would you have
strcpy
do if either argument isNULL
? Silently do nothing? Fail anassert
(which isn't an option in non-debug builds)?It's easier to opt-in than it is to opt-out. It's trivial to write your own wrapper around
strcpy
that validates the inputs and to use that instead. If, however, the library did this itself, you would have no way of choosing not to perform those checks short of re-implementingstrcpy
. (For example, you might already know that the arguments you pass tostrcpy
aren'tNULL
, and it might be something you care about if you're calling it in a tight loop or are concerned about minimizing power usage.) In general, it's better to err on the side of granting more freedom (even if that freedom comes with additional responsibility).
回答5:
The most likely reason is: Because strcpy
is not specified to work with NULL
inputs (i.e. its behaviour in this case is undefined).
So, what should a library implementer choose to do if a NULL
is passed in? I would argue that the best thing do to is to let the application crash. Think of it this way: A crash is a fairly obvious sign that something has gone wrong... silently ignoring a NULL
input, on the other hand, may mask a bug that will be much harder to detect.
回答6:
NULL checks were not implemented because C's earliest targets supported strong memory protections. When a process attempted to read from or write to NULL, the memory controller would signal the CPU that an out-of-range memory access was attempted (segmentation violation), and the kernel would kill the offending process.
This was an alright answer, because code attempting to read from or write to a NULL pointer is broken; the only answer is to re-write the code to check return values from malloc(3)
and friends and take corrective action. By the time you're trying to use pointers to unallocated memory, it is too late to make a correct decision about how to fix the situation.
回答7:
You should think of the C standard library functions as the thinnest possible additional layer of abstraction above the assembly code that you don't want to churn out to get your stuff over the door. Everything beyond that, like error checking, is your responsibility.
回答8:
According to me any function you would want to define would have a pre-condition and a post-condition. Taking care of the preconditions should never be part of a function. Following is a precondition to use strcpy taken from the man page.
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.
Now if the precondition is not met then things might be undefined.
Whether I would include a NULL check in my strcpy now. I would rather have another safe_strcpy, giving safety the priority I would definitely include NULL checks and handle overflow conditions. And accordingly my precondition gets modified.
回答9:
There is simply no error semantic defined for it. In particular there is no way for strcpy
to return an error value. C99 simply states:
The
strcpy
function returns the value ofs1
.
So for a conforming implementation there wouldn't even a possibility to return the information that something went wrong. So why bother with it.
All this is voluntary, I think, since strcpy
is replaced by most compilers by very efficient assembler directly. Error checks are up to the caller.
来源:https://stackoverflow.com/questions/3616295/why-no-sanity-checks-in-legacy-strcpy