Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Does anyone know why C calls like 'strcpy' and 'strcat' are the opposite of this?

  strcat(target, source)
  strcpy(target, source)
But, in SH...

  cp source target

I feel like these things were developed around the same time, by the same community. I've always wondered if there was a reason for the different perspective.


The reason strcat, strcpy have the destination first is because of the need to support a variable number of arguments. By definition, if the number of arguments is variable, they must be at the end. So if you think of sprintf for instance, the destination has to be first. Now, to be consistent, strcat has to behave the same and have the destination first as well, although it doesn't have a variable number of arguments.


I'm pretty sure strcpy et al pre-date the introduction of varargs. Besides, there's no reason the format string couldn't be the last argument of printf, except the specific technical detail that C requires at least one mandatory argument in any variadic function (the variable's address is used to locate the optional arguments in the stack.)


On a machine's runtime stack, there is no indication of how many parameters were passed to the function (at least on x86). C functions must use one of the mandatory arguments to determine how many arguments were pushed on the stack. In the case of the printf-family of functions, it's the number of format specifiers, e.g., "%d".


Someone once said to "What you have, then what you want" which made ALL of these easier to remember for me. In the case of strcat/cpy I think it still follows: I have an empty string 'target' and I'd like it to be 'source'.


Probably in order to be consistent with assignment.


Which is really the odd ball. In a left-to-right language, it's sort of bizarre that we don't write `4 = x' since the rvalue tends to be the more complicated part of the expression.

The curious bit is, AT&T assembly syntax does follow this convention so you'll see something like `mov $5, ax'.


Indeed. Assignment should really look like something like this this:

  expression -> variable;


Forth uses

  expression memory-location !
to store and

  memory-location @
to read.


I think it's more to do with the requirement that mandatory arguments have to go before optional ones (it wouldn't work the other way round).


In strcpy, memcpy and partners, both arguments are (rather obviously) mandatory...


Similar confusion arises from the AT&T and Intel syntaxes for x86 assembly which differ in the order of operands:

Intel:

mov bx, 100

AT&T:

mov $100, %bx

http://en.wikipedia.org/wiki/X86_assembly_language#Syntax


This is a crime against usability IMO. Another comment mentioned that tar takes arguments as "target source" rather than "source target".

Ever notice that for everything in the world that screws, like valves or screws or bottle caps, counter-clockwise loosens and clockwise tightens? How is it we got the whole world to agree on that convention, but software is 50/50 on how we order the source and destination?


My first car (a 1967 Dodge Monaco) had 'backwards' lug nuts on the left hand side of the car...

http://en.wikipedia.org/wiki/Lug_nut#History

Propane tanks also used to have backwards screwing connections. I believe this was a safety 'feature' given the mainstream use of small propane tanks. Having them tighten counter-clockwise prevents similar looking but wrong hoses from being attached to the tank. It also tricked people who didn't understand propane tanks form being able to remove a connection (since they would usually just tighten it further).


Cars generally still do have backwards nuts on the LHS. Something about vibration and direction of turn. Some of the other bolts on the LHS can be that way too.

Same with some of the LP gas cylinders I have encountered here in Aus.


Nah. I used to change tyres for a living and I never came across a car with backwards nuts on either side.


I have heard that other manufacturers originally starting using reverse-thread propane fittings to work around a 1896 Primus patent, and the situation has simply persisted.


tar is like that because of command lines

tar [args] [one thing] [list of things]

it'd be wierd if it was

tar [args] [list of things] [filename]

... but i will admit i frequently make that mistake.


tar is actually

  tar [args] [list of things]
where [args] may contain [-f filename], among other things.

That is, the destination filename is an optional argument; by default tar outputs to a tape device or stdout, depending on the implementation.

At least in GNU tar, the target filename can very well be specified as the last argument:

  tar -c foo.txt bar.txt baz.txt -f stuff.tar


good point!


But, as a counterpoint, if you want to copy several things to a folder, you do:

  cp [args] [list of things] [destination folder]


But you can also do

  cp [args] -t [destination folder] [list of things]
The same is true of mv. This is useful if you are piping filenames to xargs.


Thanks! I always wondered what was the purpose of -t. Never occurred to me it was to allow you to reverse the order of args.


I don't feel it's a crime. For that matter, I don't even prefer one over the other.

For "mv A B"

I've no problem saying either

  mv into A the contents of B
or

  mv the contents of A into B


Who does prefer one over the other? The lack of consistency is the real problem.


Except volume dials.


I conclude from this, by process of logical inference, that "louder" must be a type of "tighter".

"Forward" is also "tighter", apparently.


And sometimes doorknobs, but those are abstract enough you wouldn't expect them to behave the same. Unless you're talking about screwing the dial itself clean off.


And gas valves.


C calls are trying to mirror the assignment statement in the programming language: target := source

"cp" is trying mirror how we do things in real life: if you want to take some things from one place and put them in another, you first pick them all up (hence the first argument), walk over to the destination, and then put them down.


I suspect strcat and strcpy were parameterized as such to match memcpy.

Why memcpy was parameterized in that order, I am not certain.


memcpy(lvalue, rvalue, size)

lvalue == write location rvalue == read location

It comes from assignment syntax where the left hand side is the target of the assignment and the right hand side is the source. So this makes a ton of sense in C.

OTOH, the Bourne shell was built independent of the C programming language. The Bourne shell inherited a bit from its predecessor the Thompson shell which introduce the concept of command piping. In this case, all operations followed the pattern of data flowing to the right. This is the opposite of how assignment works in all programming languages where data flows to the left.

That's why shell commands generally move data from left to right based on their argument ordering.

FWIW, tar is unique because tar wasn't meant to do archiving to files. If you just did `tar c directory' it would archive the directory to a tape device. The `f' flag is there to redirect the output to a file (instead of the default tape device). So `tar cf foo.tar directory' is not backwards, it just uses an unusual argument convention. The modern form would be `tar --file=foo.tar create directory'.


It's similar to all the file I/O functions that always have the file descriptor first (fprintf etc). These are the heart of Unix. Remember the Unix philosophy: Everything is a file.*

* for a slightly smaller definition of everything than in Plan9


I always think that you get strcpy by first writing

   *target = source*
Step two is realizing that things don't work that way in C. Step three is sprinkling in semantic sugar to make it work.

strcat, then, is for symmetry with strcpy.


Possibly for consistency with functions that take varargs, e.g. sprintf


Most assemblers have fx

  mov a,b
as from b to a.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: