## No, and Some Systems Used the Same Convention K&R C had only a single calling convention, which is how `printf()` could be called without any special syntax or function prototype. In fact, since there were no function prototypes in C until ANSI C, there could not possibly have been different calling conventions for any implementation that also needed to compile K&R-style code, for example: ```lang-c struct FILE; struct FILE* fprintf(); int fopen(); int main() { struct FILE *outfile; outfile = fopen("hello.txt", 3); /* WONTFIX: Real code should check for errors. */ fprintf(outfile, "%s\n", "hello, world!"); return 0; } ``` There is simply no way for the compiler to tell that `fprintf` is variadic and `fopen` is not (at least, not for code other than the standard library, without doing more whole-program analysis than compilers back then did). On 16-bit x86, this led to C having a different calling convention from Pascal (with C passing its arguments in reverse order, so that the first argument of a variadic function, such as its format string, would always be at a known location, immediately before the return address on top of the stack). This is why ANSI C required varargs functions to have at least one non-variadic parameter, and for the variadic parameters to come last. Most of the special rules for variadic functions, such as the default argument promotions, exist solely for the sake of backward-compatibility with K&R C. For example, arguments narrower than an `int` widen to `int` because an `int` represented the smallest object that could be passed on the stack on word-addressed machines, and because this saved an instruction on machines that had no byte or half-word instructions. Similarly, `float` widens to `double` partly to avoid rounding error, but mainly because that was how it worked on the DEC PDP-8. The rules for pointer conversions were intended to enable K&R-style cpde such as `&dest == memcpy(&dest, &src, sizeof(dest));` that worked on K&R C (because there was no type-checking of function arguments, and all object pointers were cast to character pointers when passed as function arguments) to also compile on ANSI C, with the function prototype `void* memcpy(const void*, void*, size_t);`.