tags:

views:

536

answers:

10

All applicants to our company must pass a simple quiz using C as part of early screening process.

It consists of a C source file that must be modified to provide the desired functionality. We clearly state that we will attempt to compile the file as-is, with no changes.

Almost all applicants user "strlen" but half of them do not include "string.h", so it does not compile until I include it.

Are they just lazy or are there compilers that do not require you to include standard library files, such as "string.h"?

A: 

Most compilers provide some kind of option to force headers inclusion.

Eg. the GCC compiler has the -include option which is the equivalent of #include preprocessor directive.

Patonza
+12  A: 

GCC will happily compile the following code as is:

main()
{
   printf("%u\n",strlen("Hello world"));
}

It will complain about incompatible implicit declaration of built-in function ‘printf’ and strlen(), but it will still produce an executable.

If you compile with -Werror it won't compile.

iWerner
For the record, even with the required `#include` headers, this code is still wrong: `%d` expects a signed number, but `strlen()` returns a `size_t` which is unsigned.
Chris Lutz
Which just means that the interviewer should inform the applicant how the compiler will be called and warn them that "points" will be taken off for compiler warnings. :)
mcl
@Chris Lutz: well, it will probably "work" unless your string is REALLY long. ;)
Joe
@Chris Lutz: Thanks, I missed that one in my rush
iWerner
@Chris - even with `gcc -Wall -Wextra -pedantic` going I can't get a warning related to %d. I can get warning about the implicit int for main and the warning about no return value for a non-void function. Any idea how to get a warning for going from `size_t` to signed int here?
mcl
Still could go wrong if `size_t` is a different size from `int`. Probably best to cast the result.
Steve Jessop
The last time I ran into a problem like this was in the middle 90s, but it still applies. There is no guarantee that `size_t` is the same as `unsigned int`, and there's getting to be a lot more systems where `size_t` is 64 bits while `unsigned int` is 32 (back in the mid-90s I ran into that problem with half those sized).
David Thornley
@David: I guess the industry goes in cycles of increasing the sizes of things. Still, 64 bits will be enough for anyone, right? ;-)
Steve Jessop
@Steve - The _best_ result is to use `%zu` (the `printf()` format for `size_t`) but support for the z modifier may be spotty.
Chris Lutz
What is the z modifier?
GMan
@Steve: 64-bits might not be enough, but 128-bits ought to be enough for anybody. Consider a memory module made of pure silicon where each silicon atom can store one bit. Such a module with enough capacity to fully exhaust a 128-bit address space would be 1 story high (4 meters thick) and cover an area larger than the state of Texas (if I did my math right). I can't imagine many of those will ever be built ;)
Dan Moulding
Yes, but I might not just want to address some local piece of kit. I might want enough (virtual) space to address every byte of every computer in existence. According to the back of my envelope, 64bits is already woefully inadequate. 128bits could get dicey if humanity goes interstellar, especially once you consider that you want to carve up the space uniformly, to avoid lookup tables. So, address space should be at the very least 128 bits (for an IPv6 address), plus 128 bits to give an index into that Texas-sized doohicky of yours ;-p
Steve Jessop
@Chris: I meant "best" in the sense of "not everyone supports C99", but with suitable choice of standard, you're right :-)
Steve Jessop
@Steve: Forget interstellar: you'd have to go intergalactic. If you had 5.67e16 earth-size planets, populated with ~6.0e9 people each, 128 bits could still address one 1 terabyte of memory for each individual. That's *way* more planets than you would find in a single galaxy -- you'd need millions or billions of galaxies for that many planets. And with a computer network that size, you'd have a latency problem that would *dwarf* your addressing headaches. Like I say, 128 bits should be enough for anyone :)
Dan Moulding
But (a) 1TB of memory per person is clearly a low estimate if we assume some kind of technotopia, and (b) as I say, you don't necessarily want to have to do a `malloc` per person, you want to divide the available space hierarchically. Anyway, if we can spread across the galaxy then we can manage a switch to 128 bit pointers and (if necessary) beyond...
Steve Jessop
+2  A: 

I'm pretty sure it's non-conformant for a compiler to include headers that aren't asked for. The reason for this is that the C standard says that various names are reserved, if the relevant header is included. I think this implies they aren't reserved if they aren't included, since compilers aren't allowed to reserve names the standard doesn't say are reserved (unless of course they include a non-standard header which happens to be provided by the compiler, and is documented elsewhere to reserve extra names. Which is what happens when you use POSIX).

This doesn't fully answer your question - there do exist non-conformant compilers. As for your applicants, maybe they're just used to including "windows.h", and so have never thought before about what header strlen might be defined in by the C standard. I assume without testing that MSVC does in principle require you to include "string.h". But since "windows.h" does that for you, for the vast majority of practical Windows programs you don't need to know that you have to include "string.h".

Steve Jessop
It's more subtle than that, a header is not *required* to declare more than it is stated, but it is not *prevented* from including other headers. That a.h includes b.h should be treated as an implementation detail (if not specifically defined as part of the header).
Roger Pate
According to Michael Burr, that's a C++-only thing anyway. There's nothing in the "library - introduction" part of the C99 spec to prove him wrong, so I believe him and I've removed it.
Steve Jessop
Para 1 of 7.1.3 states that certain library identifiers are reserved if the associated headers are included. Para 2 of 7.1.3 says 'No other identifiers are reserved'. This prevents standard library headers including other headers.
fizzer
A: 

C implementations usually still allow implicit function declarations.

Anyway, I wouldn't consider all the boilerplate a required part of an interview, unless you specifically ask for it (e.g. "please don't omit anything you'd normally have in a source file").

(And with Visual Assist's "add ... include" I know less and less where they comde from ;))

peterchen
C has not allowed implicit function declarations for the last ten years. If using C89 is a requirement, it should be clearly stated. (Many people ignore the features added in C99, but that doesn't mean they believe you should use the ones removed from C89.)
Roger Pate
"please don't omit anything you'd normally have in a source file" - version control header? ;-)
Steve Jessop
"If using C89 is a requirement, it should be clearly stated." The language should always be clearly stated, unless writing "practically portable" code is supposed to be part of the challenge. Odds are maybe 1000:1 that the employer uses a conforming C99 compiler, or that the applicant has ever used one seriously. So if you're challenging an applicant to write something that will "just work", without specifying a complier or language version, then either they should assume the intersection of C89 and C99, or else you should cut them some slack for this kind of thing.
Steve Jessop
Using the intersection of C89/99 is what I meant by the part about not using features removed from C89. It's perfectly reasonable to assume that the compiler they use on the job will warn about implicitly declared functions, whether that's a (non-standard-mandated) warning or simply disallowed. Or at least I'd be very glad if they saved me the time of further interviews, if they expected me to work with archaic 20+ year old compilers (without these warnings/errors) without thinking to mention that as a requirement.
Roger Pate
Maybe a better way to put it is: "Your interview for a 'C/C++' position requires knowing the intricacies of malicious compilers from over 2 decades ago? No thanks."
Roger Pate
We know for a fact that the questioner doesn't require people to work with a warning-free C89 compiler, because the whole reason for the question is that his compiler rejected the code. So the question is not about the applicant being forced to write ancient C. It's about whether the fact that the applicant has submitted this code means that: they're lazy/arrogant and not compiling their code; or are using an unusual compiler/options that accept ancient C (like GCC does by default); or some other reason that they've missed the include, that the questioner may or may not consider reasonable.
Steve Jessop
Just as a data point, when calling `strlen()` without a prototype (in a C program, not C++), I see the following behaviors (with more or less default options): MSVC (several versions) compiles without warning, GCC 3.4.5 give a warning, Digital Mars gives an error (missing prototype). As much as some might not like it, MSVC is definitely a widely used compiler. Not ancient, not unusual, and not malicious.
Michael Burr
If you jack the warning level on MSVC up to a more sensible level, does it warn? The reason I described vanilla gcc as "unusual" is because I consider using gcc with default options to be a bit reckless. As you say, not ancient or malicious, and not necessarily wrong, but unusual. I'd apply the same to MSVC. (I tested gcc 3.4.4, btw, on the highly scientific basis that it's what I've got on my laptop. It doesn't warn, and even with `-std=c99 -pedantic` it's a warning, not an error. I guess gcc considers implicit declarations to be a GNU extension to C99...).
Steve Jessop
Thanks Michael. I've updated the wording to... be more in sync wiht reality ;)
peterchen
MSVC gives a warning starting at /W3. MSVC seems to default to /W1. I think I may modify my 'snippet builder' script to force /W4. Probably should have done that a long time ago...
Michael Burr
+3  A: 
Roger Pate
No, not in C. See 7.1.3 Reserved Identifiers in C99.
fizzer
Personally, I want coders who worry about minutiae that do matter. It really depends on the company whether it's important to be able to write pedantic code. In any case it can be tutored on the job, by rejecting their code checkins when they don't build on every platform you care about. But I would take it as a good sign if a candidate was indicating, "you haven't told me what platform this should compile on, so I've been cautious". There's knowing how to fix problems when you see them, and then there's predicting you won't get a chance to see the problem, and hence must pre-empt it.
Steve Jessop
I worry about minutiae that matters too. I don't worry about minutiae that doesn't matter, like "does my code work if I'm stranded on a desert island without a compiler". If the interview question seems more like that, it's not helping anyone.
Roger Pate
fizzer: I think I read the "C/C++" in the question title too literally, where this is true.
Roger Pate
This is mostly what my answer would have been as well. In any non-trivial program, most required headers will have already been included, so whenever I add new code, I can be reasonably confident that whatever headers the new code needs will already be there. I don't need to know exactly which ones I needed.
Rob Kennedy
+1 The job of a good programmer is to focus on those things that the compiler *can't* do well. A developer who has every include file memorized has eaten up his brain with the wrong information. There are plenty of important things to memorize. Ask them to rattle off as many GoF patterns as they know. You'll get no compiler warnings when you incorrectly implement those; so you should focus your energies on understanding them deeply.
Rob Napier
+2  A: 

If you provide a C file to start working with, make it have all the headers that could be needed from the beginning and ask the applicants to remove the unused ones.

fortran
If you want to quiz applicants on what functions and types are defined in what headers, use a separate quiz; don't lump it in with the code-writing-ability quiz.
Rob Kennedy
I don't want to quiz anyone, I was just suggesting a way to avoid the issue of the includes. It won't hurt leaving them either.
fortran
+2  A: 

The most common engineering experience is to add (or delete) a few lines of code to/from an application with thousands of lines already working correctly. It would be extremely rare in such a case to need another header file when adding a call to printf() or strlen().

It would be interesting to look over the shoulder of experienced engineers—not just graduated from school, but with extensive experience in the trenches—to see if they simply add strlen() and try compiling, or if they check to see if stdlib.h or string.h is already included before compiling. I bet the overwhelming majority do the former.

wallyk
And not to mention multi level includes...
fortran
A: 

TCC will also happily compile a file such as the accepted answer's example:

int main()
{
        printf("%u\n", strlen("hello world"));
}

without any warnings (unless you pass -Wall); as an added bonus, you can just call tcc -run file.c to execute file.c without compiling to an output file first.

Mark Rushakoff
A: 

In C89 (the most commonly applied standard), a function that is not declared will be assumed to return an int and have unknown arguments, and will compile (probably with warnings). If it does not, teh compiler is not compliant. If on the other hand you compiled the code as C++ it will fail, andf must do so if the C++ compiler is compliant.

Why not simply specify in the question that all necessary headers must be included (and perhaps irrelevant ones omitted).

Alternatively, sit the candidates at a machine with a compiler and have them check their own code, and state that the code must compile at the maximum warning level, without warnings.

Clifford
+1  A: 

I'm doing C/C++ for 20 years (even taught classes) and I guess there's a 50% probability that I'd forget the include too (99% of the time when I code, the include is already there somewhere). I know this isn't exactly answering your question, but if someone knows strlen() they will know within seconds what to do with that specific compiler error, so from a job qualification standpoint the slip is practically irrelevant.

Rather than putting emphasis on stuff like that, checking for the subtleties that require real understanding of the language should be far more relevant, i.e. buffer overruns, strncpy not appending a final \0 when hitting the limits, asking someone to make a safe (truncating) copy to a buffer of limited length, etc. Especially in C/C++ programming, the errors that do not generate a compiler error are the ones which will cause you/your company the real trouble.

Nicholaz