7 ms·
As someone who's not very well versed in C, can someone please explain how I should interpret this function signature? char *combine(s, t) char *s, *t;
by eat_veggies 6y ago
As someone who's not very well versed in C, can someone please explain how I should interpret this function signature?
char *combine(s, t)
char *s, *t;
{
- stephc_int13 6y agoThis is ugly old style C function signature. Obsolete since a long time ago (more than 20 years) Here is the "modern" equivalent: char combine(char s, char* t) {
- rwmj 6y agoUgly? I rather miss the traditional style of argument passing. My first real paid job used Microware's OS-9 compiler which only supported the traditional syntax, did absolutely no optimisation that I could discern, and made you use "register" if you wanted a local variable assigned to a register instead of always being spilled to the stack. (In fact looking back at it now I wonder if it was just a rebadged PCC). As an aside it's not always more verbose because you can group parameters by type, eg: int foo (c1, i1, c2, i2) char c1, c2; register int i1, i2; { ...
- saagarjha 6y agochar *combine(char *s, char *t)
- azdavis 6y agoThis is an old way of writing the type of parameters to a function. I believe the modern equivalent is char* combine(char* s, char* t) { ... } which means combine takes in two pointers-to-char and returns a pointer-to-char. Opinions differ on whether the * should be next to the type or next to the identifier. I prefer putting it next to the type.
- inspector-g 6y agoWhen I was learning C a couple decades ago, pointer syntax never made any sense to me until something suddenly clicked with “put it directly next to the type name and not next to the variable name”. Ever since then I have not been able to figure out why it is commonly taught next to the variable name. I mean, short of enabling declarations like: char *a, *b; But I have long since found the tradeoff to be worth the syntactic clarity.
- bluejekyll 6y agoI find it to be clear to have the * with the type. Otherwise it can be confused (not by the compiler but the reader) that you are dereferencing the variable a or b.
- _hexley_ 6y agoIn my own projects, I like to put the * on its own, like so: int const * const i; This is nice because you can naturally read the signature from right to left. "i" is a constant pointer to a constant integer. It's a little unconventional, but I think it's a really clear way to convey the types.
- wrs 6y agoThe type of a is char * . Some people (me included) find it clearer to write the type, followed by the variable name. So just as you’d write int a , you’d write char* a . The fly in this ointment is that C type syntax doesn’t want to work that way. It’s designed to make the definition of the variable look like the use of the variable. A clever idea, but unlike nearly every other language, which BTW is why I think you should really use typedefs for any type at all complicated in C. For example, the type-then-variable style falls down if you need to declare an array int foo[4] or a pointer to a function returning a pointer to an int int *(*a)(void) (...right?). So I’m perfectly willing to do it the “C way”, I just find out more readable to do it the other way unless it just won’t work (and then prefer to use typedefs to make it work anyway). Note that this was rethought for Go syntax.
- deleted 6y ago[deleted]
- ramshorns 6y agoIs it equivalent? Because that seems to be the only difference between the two editions for the newprint function, and the author says one of them happens to compile. https://wozniak.ca/blog/2018/06/25/1/code.html https://wozniak.ca/blog/2018/06/25/1/code.html
- account42 6y agoYes, the declarations are equivalent. The difference is the function prototype `void newprint(char *, int);` at the start, which is missing in the second example. With the forward declaration, the compiler knows what arguments newprint takes and errors out if you pass something else. C is compiled top to bottom so in the older version of the example the compiler has no way of knowing what number of arguments the function takes at the point whree it is called. In (not so) old versions of C that implicitly declared a function taking whatever you passed it.
- 1vuio0pswjnm7 6y agoTake a common idiom like main(int argc, char **argv) These all produce the same result main(int argc, char* *argv) main(int argc, char** argv) main(int argc, char* argv[])
- bregma 6y agoIn C, char * a; declares a variable, `a` that, when dereferenced using the `*` operator, will yield an int. In C++, the same line declares a variable, `a`, of type `pointer-to-int`. C cuddles the asterisk up to the variable name to reflect use. C++ cuddles it up to the type because it's a part of the type. Opinions don't really differ on whether C-style or C++-style is better, but a lot of cargo-cult programmers don't bother adjusting the style of the code snippet they paste out of Stack Exchange so you see a lot of mixtures.
- deleted 6y ago[deleted]
- userbinator 6y agoThat is pre-ANSI C. The parameter types are declared between the end of the argument list and the start of the body, instead of inside the argument list.
- bumblebritches5 6y agothat's a K&R style function definition. modern syntax is: char *Combine(char *S, char *T) { ... } which means the Combine function returns a string (char pointer), and takes as arguments two strings, S and T.
- sys_64738 6y agoWas it the ANSI Std that did away with this style? Can't recall.
- xenadu02 6y agoANSI adopted function prototypes from C++ in C89. Originally C had no type checking on function parameters. All arguments were promoted to word width and pushed to the stack. If you gave a function fewer arguments it would just read garbage off the end of the stack. If you gave it excess arguments they were silently ignored.
- _kst_ 6y agoSort of. ANSI introduced prototypes, but old-style function declarations and definitions, though they were declared obsolescent, remained valid (i.e., any conforming C compiler is still required to support them). As of the 2011 standard, that's still the case. I think that C2X will finally remove them.
- ridiculous_fish 6y agoTo add some flavor to the other answers, in K&R C the parameter passing was very uniform: everything (save doubles) got promoted to word-size and pushed on the stack. chars (and shorts) became ints. You couldn't pass aggregates. doubles were a problem, but were rare. Because the parameter passing was uniform, you didn't need to inspect anything at the call site. All functions get called the same, so just push your params and call it. Types were for the callee and were optional. This is what powered printf, surely the highest expression of K&R C. In modern C-lineage style, we enumerate our formal parameters, and variadic functions are awkward and rare. But LISP and JavaScript embrace them; perhaps C could have gone down a different path.
- stkdump 6y agoAs far as I know, the promotion to word size (now 32 bit) still happens. Also if you have more than a fixed number of params (defined by the platform ABI), parameters are still pushed on the stack. You can't push 8 or 16 bit values on the stack. The stack pointer is always a multiple of 4. The interesting thing is that with K&R C a function declaration/prototype is optional. That means you can call a function that the compiler has not even seen. Mismatches in parameter/return types (which are optional and default to int in declarations as well) are normally not a problem, because of the aforementioned promotion. If you have the declaration, then the compiler will at least let you know about wrong number of arguments.
- linkdd 6y agoAs the others already said, it's the old way of declaring the arguments type. But I think it's good to know other pitfalls: - The "default" return type of a function is int - A function that does not use void to tell that it takes no argument just have an undefined number of parameters See this example: https://ideone.com/GfwS4O https://ideone.com/GfwS4O You could in theory use the address of a local variable (allocated on the stack) to access the arguments passed to the function directly on the stack. But this is just madness... Or is it ? Isn't C just assembly with a "nicer" syntax ?