Proficient at C

J

jaysome

When we are looking to hire C programmers, we inevitably receive
resumes from people who claim they are "proficient at C", or something
to that extent.

For those who claim they are "proficient at C", what are some good
questions to ask them to determine if they are really "proficient at
C", as they claim?

I can think of one good question:

Which of the following definitions of main are acceptable by a
portable Standard C implementation?

A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.

What other good simple, basic questions are there (e.g., don't cast
malloc)?

Thanks
 
R

Richard

jaysome said:
When we are looking to hire C programmers, we inevitably receive
resumes from people who claim they are "proficient at C", or something
to that extent.

For those who claim they are "proficient at C", what are some good
questions to ask them to determine if they are really "proficient at
C", as they claim?

I can think of one good question:

Which of the following definitions of main are acceptable by a
portable Standard C implementation?

A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.

What other good simple, basic questions are there (e.g., don't cast
malloc)?

Thanks

If you are hiring people I would suggest you ask the best people you
have. "proficient" means different things to different companies.


Here you would find people who insist your code compiles on a PDP/xxx
from 20 years ago. Realists would suggest you find someone proficient on
your platform(s) of choice who is good with a debugger and can handle
other peoples code.
 
W

Walter Roberson

jaysome said:
I can think of one good question:
Which of the following definitions of main are acceptable by a
portable Standard C implementation?
A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.
BTW, the correct answer to the above question is A, C, E and F.

It depends which version of the Standard the implementation adheres
to. None of your definitions return a value from main, so the
behaviour is implementation defined (or is it undefined, I'd have
to check the exact wording) in C89/C90. In C99 such cases automatically
return 0 from main, rendering the behaviour well-defined.
 
D

Dan

jaysome said:
When we are looking to hire C programmers, we inevitably receive
resumes from people who claim they are "proficient at C", or something
to that extent.

For those who claim they are "proficient at C", what are some good
questions to ask them to determine if they are really "proficient at
C", as they claim?

I can think of one good question:

Which of the following definitions of main are acceptable by a
portable Standard C implementation?

A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.

What other good simple, basic questions are there (e.g., don't cast
malloc)?

I think it WAY more important to get people who can acutally program rather
than those who remember some of the finer points of a language. I had people
who didn't know what a function pointer were who were way better coders and
knew how to look up something and learn it when they didn't know. All the
people who did know knew everything about C, but had no clue how to use it
to actually solve a problem. I would focus questions more around how they
would implement an algorithm or solve a problem. How they would use dynamic
allocation and linked lists etc. What they would do to look up a stdlib
function to see how it works. Where to look to make sure something is
portable etc. Maybe im just saying that because I coded C for years without
knowing only C was valid and E wasn't.
 
P

Paul Hsieh

jaysome said:

Ask them to write a function which *outputs* a string. How they
handle pointers and storage is key to demonstrating their
understanding of how to program in C.
I can think of one good question:
Which of the following definitions of main are acceptable by a
portable Standard C implementation?
A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.

This is not a good question. Whatever your compiler accepts is good
enough, and if another doesn't this couldn't be more than a 10 second
fix. There are cases where being pedantic about the standard is so
truly and utterly useless. This is one of of those cases.

If you care to address the standard, throw in a third parameter that
represents the environment variables and ask the candidate to address
that.
A, C, E, F, although for maximum acceptabilititude you will want to put a
return statement in between those braces...

I would extend the list to include a const modifier for argv, and if anyone
specifically marked it either as /right/ or as /wrong/ (as opposed to just
choosing G or H), I'd ask them why. They might well get the acceptability
aspect wrong, but for an excellent reason. Remember, you're not after
perfection, but after proficiency.

Otherwise, the above question doesn't really deal with proficiency, although
it does help you to weed out the incompetent.

This question is unlikely to be very good at discerning the ability of
someone to program. However, if you have a candidate that insists
that putting this cast is a bad idea, you should probably consider
walking the candidate out immediately. That kind of ideologue
especially going the wrong way, is likely to be a problem candidate.
Well, you could word it better than that. For example: "the practice of
casting the return value of functions returning void *, such as malloc, is
ancient and widespread. Is this necessary? If so, why? If not, why not? Was
it ever necessary in the past? If so, why? Is it good practice? If so, why?
If not, why not?"

In other words, has the candidate heard of the C++ programming
language. But the OP has not listed that as amongst his criteria.
Here's another, which is in several parts.

Consider a frame buffer that is described by the following data structure:

struct gfx_fb_
{
unsigned long **buffer;
size_t rows;
size_t columns;

};

typedef struct gfx_fb_ gfx_fb;

Pixel (x, y) is represented by buffer[y][x].

You have five minutes. Write a function with this interface:

int floodfill(gfx_fb *fb, size_t x, size_t y, unsigned long colour);

to replace a contiguous patch of colour with the new colour passed in as the
fourth parameter.

(Obviously we can't expect a perfect job in five minutes,

int floodfill (gfx_fb *fb, size_t x, size_t y, unsigned long colour) {
int counter;
unsigned long currentColor;

if (NULL == fb || x said:
return 0;

currentColor = fb->buffer[y][x];

if (currentColor == colour) return 0;
fb->buffer[y][x] = colour;
counter = 1;
if (y > 0 && currentColor == fb->buffer[y-1][x])
counter += floodfill (fb, x, y-1, colour);
if (y < fb->rows - 1 && currentColor == fb->buffer[y+1][x])
counter += floodfill (fb, x, y+1, colour);
if (x > 0 && currentColor == fb->buffer[y][x-1])
counter += floodfill (fb, x-1, y, colour);
if (x < fb->columns - 1 && currentColor == fb->buffer[y][x+1])
counter += floodfill (fb, x+1, y, colour);

return counter;
}

About 2-3 minutes?
[...] but we'd expect the
basics. Almost certainly the candidate will go for the naive recursive
implementation, on the grounds that anything else is likely to take him more
than five minutes!)
Sure.

Follow-up (and this is the important one): look at the code you've just
written - what would you say is wrong with it?

Its fully recursive. By changing the interface, its possible to
remove the redundant pixel reads and redundant coordinate bounds
checking. You didn't say what you wanted returned; i just assumed
"number of pixels updated" was good enough.
A proficient C programmer will:

* point out any obvious syntax bugs, basically doing a quick clc on it;

Its hard for me to judge myself on this. But that's what compilers
are for.
* show how the recursion is broken (if indeed it is);

I highly doubt that it is.
* explain how, given more time, he would make the function more robust (for
example, does the code "fall off" the edge of the image? Not to worry if it
does, but does he *spot* that it does?);

Unless I have made a mistake, the code is robust. (Aren't tautologies
awesome?)
* illustrate how the efficiency might be improved.

A hand generated stack would work just fine (this is a case where a
block based memory pool/arena allocator is much better than straight
malloc). You would also want to be clever in doing horizontal spans
in terms of direct fills as well as what you put into your hand
generated stack.

The result would be somewhat complicated. Designing a unit test for
it does not seem that complicated -- but its not clear how good
coverage you can get in a reasonable amount of CPU cycles.
 
B

Ben Bacarisse

Paul Hsieh said:
On Jun 11, 12:24 am, Richard Heathfield <[email protected]> wrote:

In other words, has the candidate heard of the C++ programming
language. But the OP has not listed that as amongst his criteria.

That is not the only reason why it is/was widespread. It took me ages to
unlearn it since it was common in K&R C (malloc returned a char *).
Of course knowing this history favours a particular kind of applicant
which the OP might or might not want!
 
P

Paul Hsieh

Paul Hsieh said:


This is like void main - only a truly incompetent programmer could foul it
up.

Right, but I need to know whether the candidate deals with string at
the average level of people who post here in c.l.c. or whether they
are a candidate worthy of real consideration. Some people don't get
the fact that you cannot return a string that you declared as an array
in the inside of your function, or that use of statics inhibit multi-
threading. Enough people that its worth testing that.
Much laughing. So a Fortran program is good enough, provided you're using
a compiler that accepts Fortran? I Don't Think So.

Which of the options listed (that you have deleted from the thread, of
course) do you think a Fortran compiler will accept?
Portability has its benefits, whether you realise it or not.

*Cough* straw man *cough*.
If you insist on disagreeing with the candidate, then yes, of course,
thank him for his time and let him go - there's no point hiring a bright
guy if you're not going to listen to him.

"Bright guys" besides being a subjective turn, can do all sort of
intolerably wrong things (there is even a movie about this based on
the book: "The Smartest Guys in the Room" that is worth watching).
Productivity, and understanding the real world of coding (not this
strange fantasy world that CLC seems to operate in) kind of matters.
Code may and likely will migrate to C++, that's just a general
principle that people should be aware of, that's far more important
that someone's bad argument for avoiding a useful cast.
So you think of "getting it right for good reason" as being an ideology,
and presumably an ideology with which you disagree? Well, so be it.

Whatever, I only have evidence and measurable data on my side. (I
have never written a line of C code in my professional code that
didn't eventually get handed to a compiler that could do, or *did* do C
++.)
Two wasted tests. x and y are unsigned types.

You have to be kidding me. There is a *GARGANTUAN* amount of waste in
my routine, even ignoring the recursion, and you managed to isolate
the most irrelevant? (And if you look again, it does appear to be
*three* wasted tests, as fb cannot spontaneously become NULL as it
gets passed recursively.) In graphics, you tend to ignore these
things when bandwidth to pixel data is a factor.

Look, like many of the other problems with my solution, the originally
proposed *INTERFACE* limits my ability to do this right. In this
case, you went and made the coordinates unsigned for some bizarre
reason. Anyone who knows basic graphics or has been in the graphics
industry for even a short time knows that you never do this -- it will
muck up all of your standard clip algorithms. My natural tendency is
to do things as they are really meant to be done and ignore errors in
design; in this case the prototype.

If that was supposed to be "a trick question" kind of thing, it seems
like a fairly shallow and also valueless trick (its not like array
reversal, where the trick of making sure your index only goes half way
through is fundamental to getting it right.)
[...] But you will be pleased to hear
that the code does actually do its job, albeit rather slowly.
About 2-3 minutes?

A candidate who wasted his spare time staring into space instead of
finding those redundant tests would not be doing himself any favours.

As opposed to the time I spent agonizing over this interface and how
it forces me to read back each pixel at least twice? You have a
bizarre sense of priority.
[...] but we'd expect the
basics. Almost certainly the candidate will go for the naive recursive
implementation, on the grounds that anything else is likely to take him
more than five minutes!)
Follow-up (and this is the important one): look at the code you've just
written - what would you say is wrong with it?
Its fully recursive.
Right.

By changing the interface, its possible to
remove the redundant pixel reads and redundant coordinate bounds
checking.

You don't need to change the interface to at least make a start on that.
(I won't explain further, because you explained it yourself - "direct
fills" - further on in your article.)

No what I meant was that the interface should include the color from,
use *signed* integer coordinates, and guarantee that the incoming
coordinates are in bounds. Look closely. My solution reads each
pixel twice (once to decide whether it should recursively flood fill
there, and once to figure out which color its trying to match) and it
checks for being in-bounds twice (once upon input, and once for each
of the four recursions.)
 
C

Chris H

Malcolm McLean said:
There's no point asking trivia about the C standard. Someone might be a
very good C programmer but simply never have used the language in an
environment where strict adherence was important.

Shirley not? Aren't all C/C++ compilers standards compliant?

This is the problem compilers are mostly C90-C95 to C99(ish) with
extensions. To use C practically on most embedded systems you need to
use the extensions.

Unfortunately I can see the next C++ standard going the same way a s the
C99 standard.

I think it is time for the next C and C++ standards to slim down to a
core language definition with guidance in appendices for things like
complex maths.
 
I

Ian Collins

Malcolm said:
There's no point asking trivia about the C standard. Someone might be a
very good C programmer but simply never have used the language in an
environment where strict adherence was important.

Good point, I once went for an interview for an embedded job where the
interviewer spent more then half the time on questions about printf and
scanf format specifiers. I hadn't used either except for simple debug
output for years before and never used them once on that job...
 
I

Ian Collins

Chris said:
Unfortunately I can see the next C++ standard going the same way a s the
C99 standard.
If you're talking adoption, that's unlikely, people actually want the
new features and most of the library extension are here now.
I think it is time for the next C and C++ standards to slim down to a
core language definition with guidance in appendices for things like
complex maths.
Luckily C++ has been spared that complex nonsense.
 
S

Serve Lau

Richard Heathfield said:
Not at all. You claim that this whole main() thing is one of the cases
where
being pedantic about the Standard is truly and utterly useless, whereas in
fact it's one of those cases where knowing the language spec allows you to
write a maximally portable entry point for your program - so as far as I
can
see, your claim is simply wrong. Not a strawman in sight.

I dont think the whole void main is a problem in terms of portability. The
chance that it will compile on the new system too is big and if it doesnt
its only two lines to change. I agree it's a bit of a shame that so many
beginning C coders learn that void main is correct and have to unlearn it
but in my eyes the enormous amount of effort spent by experienced C coders
to get rid of this "evil" is more of a shame. Letting it rest, do it
yourself the correct way and let others know only when they ask about it
would put focus on more important things.
I know, I'm spending time on it too now. Got some spare time atm and it wont
happen again :)
 
O

Old Wolf

When we are looking to hire C programmers, we inevitably receive
resumes from people who claim they are "proficient at C", or something
to that extent.

I can think of one good question:

Which of the following definitions of main are acceptable by a
portable Standard C implementation?

A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }

Surely it would be better to ask them to write
a program to accomplish some task. Then you would
find out if they can define main correctly, and
a whole lot else.

Do you want a good programmer, or an expert on C trivia?
 
I

Ian Collins

Richard said:
Old Wolf said:



A good C programmer will be both.
Not necessarily. I've known may a very good C programmer who (like me
with format modifiers) never uses parts of the language not relevant to
their chosen field. Are you an expert on C's complex numbers?

Just because someone can quote chapters of the standard verbatim,
doesn't mean they can apply C successfully to real world problems.
 
S

santosh

Serve said:
I dont think the whole void main is a problem in terms of portability.
The chance that it will compile on the new system too is big and if it
doesnt its only two lines to change. I agree it's a bit of a shame
that so many beginning C coders learn that void main is correct and
have to unlearn it but in my eyes the enormous amount of effort spent
by experienced C coders to get rid of this "evil" is more of a shame.

Actually "correcting" newbies who use void(main) virtually always
consists of a small line within the overall post. Quite a trivial
effort. The really unproductive discussions are the ones between
regulars concerning the subject, often exploding into dozens of posts
consisting of fine nitpicking and debates on the semantics of section
5.1.2.2.1.
Letting it rest, do it yourself the correct way and let others know
only when they ask about it would put focus on more important things.

Often newbies don't know where they have gone wrong. Waiting for them to
ask about it themselves will risk making the error permanent.
 
C

Chris H

Ian Collins said:
If you're talking adoption, that's unlikely, people actually want the
new features and most of the library extension are here now.

No I was reflecting on the chatter on one of the internal ISO-C++
panels over the last two days
Luckily C++ has been spared that complex nonsense.

And there was me thinking that C++ was going to adopt all the C
libraries or is that off again?
 
I

Ian Collins

Chris said:
No I was reflecting on the chatter on one of the internal ISO-C++
panels over the last two days


And there was me thinking that C++ was going to adopt all the C
libraries or is that off again?
C++ already supports complex numbers, so I don't think C99 complex
numbers would be applicable or compatible. You'd have to check
elsewhere to be sure.
 
L

lawrence.jones

Ian Collins said:
C++ already supports complex numbers, so I don't think C99 complex
numbers would be applicable or compatible.

It wouldn't be applicable, but the intent was to make the C99 complex
support as compatible as possible with the C++ complex (i.e., to make it
possible to write code that works with either one with just a little bit
of extra effort).

-- Larry Jones

Honey, are we out of aspirin again? -- Calvin's Dad
 
K

Keith Thompson

Richard Heathfield said:
Tony Mc said:
A. int main(void) { /*...*/ }
B. void main(void) { /*...*/ }
C. int main(int argc, char *argv[]) { /*...*/ }
D. void main(int argc, char *argv[]) { /*...*/ }
E. int main(int argc, char **argv) { /*...*/ }
F. int main(int count, char **args) { /*...*/ }
G. None of the above.
H. All of the above.

H includes G which contradicts itself. That's a sort of Russell
paradox. I'm not sure what that would mean in interview.

It means you'll either get thrown out for being a smartalec or given the job
on the spot (depending on whether or not the interviewer has a PhD in
mathematics, symbolic logic, or similar).

The fact that H contradicts itself isn't a problem, since not all of
the above, even excluding G, are valid.

(I'm still waiting for C to implement the exclusive-and operator,
meaning "A and B, but not both". Like && and ||, it can have
short-circuit semantics; unlike && and ||, it doesn't have to evaluate
*either* operand.)
 
R

Ron Ford

(I'm still waiting for C to implement the exclusive-and operator,
meaning "A and B, but not both". Like && and ||, it can have
short-circuit semantics; unlike && and ||, it doesn't have to evaluate
*either* operand.)

I recently got my head around || as a shortcircuit operator and thought
that its "or-ness" is what made it work.

What would either inclusive or exclusive 'and' look like as a short circuit
operator?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top