7

I have just seen two interview questions for which I was unable to find any satisfying answers.The questions are

  1. How many levels deep can include files be nested?
  2. When should a type cast not be used?

Can anyone explain the answers to me?

Thanks in advance.

Mia Clarke
  • 8,134
  • 3
  • 49
  • 62
Maddy
  • 503
  • 4
  • 12
  • 21
  • 2
    No offense, but these aren't very good interview questions. They don't show anything about your ability to think on your feet or to solve novel problems. I'd be skeptical about any company asking you these questions in an interview; it doesn't seem like they're looking for the right things in an engineer. – templatetypedef Jan 28 '11 at 10:59
  • IMHO mixed in with thinking questions it would be useful for finding people who truly know the language deeply and a good starting point for discussions on a number of issues. – Flexo Jan 28 '11 at 11:03
  • @Ashot - path length has no direct link to maximum allowable #include nesting. Whilst it is implementation defined, almost always each file is opened individually (unless they're mostly relative paths, which would seem unlikely), the names don't get concatenated and the path length doesn't grow. – Flexo Jan 28 '11 at 11:06

4 Answers4

11
  1. Any limit is implementation-defined, but the standard requires at least 15, see 5.2.4.1

  2. Same conditions as anything else: when it's wrong, and when it's unnecessary. Most famous example is probably that you shouldn't cast the return value from malloc. It's pointless[*] and it could hide an occasional bug (forgetting to #include stdlib.h). Another example is that if you randomly scatter casts between integer types, then eventually you'll suppress a compiler warning for a narrowing cast or a comparison between signed and unsigned values, that you should have paid attention to. Casts to suppress such warnings shouldn't be placed until you're sure the code is right.

[*] I used to think there was a point, because I'd write things like:

foo *p = something;
... some time later ...
p = (foo*) malloc(n * sizeof(foo));

The cast provides some protection against a bug - using the wrong type in the sizeof. Visually I can see that the cast matches the sizeof, and the compiler checks that the variable matches the cast, so I have safety.

Now I write:

p = malloc(n * sizeof(*p));

I don't need a check for safety, because I've certainly allocated memory of the correct size for the type of p. Well, assuming the multiplication doesn't overflow.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • If you forget to include then the standard-compliant compiler won't recognize malloc. You should only use standard C compilers. – Lundin Jan 28 '11 at 11:56
  • As for the malloc cast, how can it be protection when neither the compiler nor a static checking tool would catch the bug? To me it would rather seem risky to have your mindset, as you would perhaps write sizeof(foo*) by accident to match the type in the typecast. This is *not* the reason there are typecasts before malloc, and they aren't entirely pointless either. The *real* reason is compatibility between C and C++, where the former language allows implicit casts from void* while the latter doesn't. – Lundin Jan 28 '11 at 11:57
  • @Lundin: A C99 compiler won't recognise `malloc`, a C89 compiler will. It's some time ago I was doing this, and as I say I'm not claiming it's good practice. It provides safety in the sense that `bar *p; ... ; p = (foo*) malloc(n*sizeof(foo));` fails to compile. Compatibility between C and C++ is a very poor reason, even if it is real, since it's asking for trouble to compile C code as C++. If you want to use it in a C++ program then compile it as C and link it from C++, don't try to write in an imagined language consisting of the intersection of C and C++. – Steve Jessop Jan 28 '11 at 13:50
  • "you would perhaps write sizeof(foo*) by accident to match the type in the typecast" - not that I recall, whereas I do recall occasionally assigning to the wrong variable, and the type mismatch catching that. – Steve Jessop Jan 28 '11 at 13:52
  • @Steve Why wouldn't a C99 compiler recognize malloc? It is part of the C99 standard, so it darn better do. I do think that the typecast is poor practice no matter the reason, I never write it myself. But the reason why you see that cast so often in C code *is* because there's a lot of dummy programmers compiling their C code under a C++ compiler that is set to compile C++. – Lundin Jan 28 '11 at 13:58
  • @Lundin: First "the standard-compliant compiler won't recognize malloc", then "why wouldn't a C99 compiler recognize malloc". The old danger in C89 was the implicit definition of `malloc` with `int` return type can yield silently broken code if you cast. IMO this was rarer than the bug you avoid with the cast. Amusingly CERT issued 2 security advisories, one saying "always cast" and later "never cast". I think we're agreed what the right thing is, and that the cast in fact is pointless. If someone else has different faulty reasons from my old faulty reasons, then that's their business :-) – Steve Jessop Jan 28 '11 at 14:06
  • @Steve I'm not sure I'm following you, what implicit int definition? malloc has always returned an explicit type, void*, as far as I know. – Lundin Jan 28 '11 at 14:27
  • @Lundin: if you call a function without a declaration in scope, the compiler assumes that the function returns `int`. So under C89, if you forgot to include `stdlib.h`, the return value from `malloc` would be treated as an `int`. If you leave the cast off, the compiler will issue a diagnostic to the effect of "assigning integer to pointer without a cast". With the cast, you'd supress the diagnostic and potentially have runtime issues, since converting a pointer value to an int and back again isn't guaranteed to be meaningful. – John Bode Jan 28 '11 at 15:23
  • @John This is the same for C99 though? AFAIK functions without a prototype is suggested as an obsolete mechanism by the committee, but it has not yet made it to the standard. Right? – Lundin Jan 28 '11 at 15:48
  • @Lundin: Implicit typing is no longer allowed as of C99, so that particular failure mode no longer applies. A lot of people are still working in C89, though. – John Bode Jan 28 '11 at 16:41
2
  1. As the other answer has pointed out is implementation defined, but there are problems (especially with build times) that are likely to arise from large chains. It might be a "code smell" too indicating poor encapsulation.

  2. The simplest answer is "when it's not needed", i.e. automatic, e.g. float to double, int to long (when appropriate[*]). I would assume too that it is almost certainly asking about casting from void * to something else, e.g. with malloc (comp.lang.c FAQ item).

[*] See comment

Flexo
  • 87,323
  • 22
  • 191
  • 272
  • int to long may certainly need typecasts in plenty of cases, to prevent accidental changes in signedness caused by the integer promotion rules. – Lundin Jan 28 '11 at 11:58
2
  1. What a bad interview question! That you don't know this says something good about you. People who know things like that without looking them up in the standard are best described as eerie nerds :)

2.

  • It should preferrably not be used to remove const or volatile qualifiers.
  • It should in most cases not be used to cast between pointers pointing at different types.
  • It should not be used to cast between function pointers of different types.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • "What a bad interview question" - sort of, depends what counts as a "correct answer". If I was asked this in an interview, I wouldn't know the answer but I'd know where to look it up. Without wanting to over-praise my own achievement here, people who know where to look things up are valuable. Good interviews do not give you one point per piece of trivia you know, and hire the person with the most points, but I think a trivia question can still start a useful discussion. For example, awoodland's answer tells you something about his knowledge of larger projects. – Steve Jessop Jan 28 '11 at 10:57
  • @Steve - It's quite open-ended, which would allow a lot of discussion and an "I know it's an issue, I know how to look it up" answer from a good candidate could probably be extracted by a good interviewer. – Flexo Jan 28 '11 at 10:59
  • @Steve I hold C programming interviews myself now and then. And based on experience, I think the question is bad, because whether they know this is an issue or not, you would get the same answer "I don't know, I would look it up". And you can't tell how good the candidate would be at actually looking it up. A better question would be: are there any risks with nested include files? Still, that question is of mild interest and there are many better ones to ask on the limited time you have on an interview. – Lundin Jan 28 '11 at 11:49
0

There is no limit on how deep it can be nested, but your compiler may run out of stack space... so this is compiler-dependent!

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268
garima
  • 5,154
  • 11
  • 46
  • 77