C++ Puzzle

J

James Kanze

Puzzle for the newbies (trivial for more experienced
programmers, but might be a bit challenging for a newbie):
Write a "hello world" program which does not use any
preprocessor # directives.

Impossible in pure C++, since no I/O is accessible without an
#include.
 
J

James Kanze

Hmm... The answer is so plain and non-interesting that it will
probably disappoint you. Let me give you a little hint :)
As you probably know, the '#include' directive simply
_inserts_ the content of some other file into the current
translation unit.

That's true for #include "...". #include <...> is a bit more
Now, in order to write a simple Hello-World program, we'd
probably have to do '#include <stdio.h>'. Imagine that instead
of doing '#include <stdio.h>' we simply take the content of
'stdio.h' and copy-paste it into the source code of our
Hello-World program.

Suppose that, instead, there was no file named stdio.h on the
system. That the compiler simply triggered on the string
"#include <stdio.h>" to unlock something precompiled into the
symbol table.
 
P

Pascal J. Bourguignon

James Kanze said:
Impossible in pure C++, since no I/O is accessible without an
#include.

What about:

extern "C"{
int write(int fd,char* buffer,int size);
int read(int fd,char* buffer,int size);
}


or even:

{
volatile unsigned char* cmdreg=(unsigned char*)0xff00001be;
volatile unsigned char* datareg=(unsigned char*)0xff00001bf;
for(int i=0;i<5;i++){
cmdreg=0x10;datareg="hello";cmdreg=0x11;
}
}
 
J

Jean-Marc Bourguet

James Kanze said:
you're required to use <...> for the standard headers.

My understanding is that you can use "..." at the risk of having a source
file masking the header.

Yours,
 
R

red floyd

James said:
Impossible in pure C++, since no I/O is accessible without an
#include.

How about:


extern "C" int printf(...);
int main()
{
printf("hello world\n");
}
 
S

Sherm Pendley

Juha Nieminen said:
Compiles and works at least with gcc, so it's good enough for me.

Agreed, except that I'd suggest this:

printf("%s", "hello world\n");

Abusing the format string is not dangerous in this particular example,
but if it's a learning exercise it should encourage good habits.

sherm--
 
J

James Kanze

My understanding is that you can use "..." at the risk of
having a source file masking the header.

Sort of; it depends on what you mean by ``use "..."''.
According to the standard, if it is unable to find the file
corresponding to "...", it then reprocesses the directive as if
it were <...>.

The important point, of course, being that the compiler can
recognize ``#include <iostream>'' or whatever as a sort of an
extended keyword, and trigger some internal actions which makes
whatever is necessary visible, without there being files or any
other external support.
 
J

James Kanze

What about:
extern "C"{
  int write(int fd,char* buffer,int size);
  int read(int fd,char* buffer,int size);
}
{
    volatile unsigned char* cmdreg=(unsigned char*)0xff00001be;
    volatile unsigned char* datareg=(unsigned char*)0xff00001bf;
    for(int i=0;i<5;i++){
       cmdreg=0x10;datareg="hello";cmdreg=0x11;
    }
}


I'm not sure that I'd call those pure C++:). With regards to
the first, of course, it's likely to compile, and then do
something wierd. Posix also says that you have to include
<unistd.h> in order to access write and read (and of course,
they don't have the signatures you just gave, so technically,
you would have undefined behavior anyway); I started to propose
something similar, and gave up trying to find all of the
typedef's in different headers. (There was a time, however,
when this sort of thing worked in C.)

As for the second, it looks awfully implementation dependent to
me:).
 
J

James Kanze

How about:
extern "C" int printf(...);
int main()
{
     printf("hello world\n");
}

I can't imagine it failing, but the standard says that you have
to include the appropriate header if you use a standard
function. Otherwise, it's undefined behavior. (And of course,
no experienced programmer would do such a thing, so the idea
might not occur to him.)
 
J

James Kanze

puts("hello world");
This whole example would make a lousy learning exercise,
anyway.  In particular, ::printf isn't guaranteed to exist
(even though it sometimes "works").

That's a good point; it's only guaranteed to "exist" if you
include <stdio.h>, and it could be an inline function forwarding
to std::printf (or some other function in the implementation's
namespace) there, and it isn't specified whether it is extern
"C" or not. Except that perhaps the Red wasn't trying to access
but the one in C; that one is said:
I don't know whether it's technically UB to open namespace std
just wide enough to declare printf, but it probably ought to
raise an eyebrow or two.

And that one too could be inline, forwarding to something else.
In which case, you run afoul of the requirement that if a
function is declared inline, it be declared inline in every
translation unit which uses it.
 
S

Sherm Pendley

Jeff Schwab said:
This whole example would make a lousy learning exercise, anyway.

Yes, the whole thing seems rather contrived - of what practical use is
learning to output a string in C++ without #include <iostream> anyway?

sherm--
 
J

Juha Nieminen

Sherm said:
Yes, the whole thing seems rather contrived - of what practical use is
learning to output a string in C++ without #include <iostream> anyway?

Nobody required for these puzzles to be actually useful. ;)
 
S

Sherm Pendley

Juha Nieminen said:
Nobody required for these puzzles to be actually useful. ;)

Is that like a meta puzzle then, trying to figure out the real-world
relevance of the puzzle? :)

sherm--
 
N

Noah Roberts

Andrey said:
The funny part, of course, is that this is an _the_ _correct_ _answer_.
Member subobjects are always constructed in the order of their
declaration. And member subobjects are always destructed in the reverse
order of their declaration. So yes, they are destroyed in the reverse
order of their initialization.

On top of that, as I said before, this all has absolutely noting to do
with automatic variables...

Gotta love it when interviewers try to get too damn clever for their own
good. Such a detail shouldn't even really matter in production code
anyway. It's a trivia question.
 
B

Bill Davy

Noah Roberts said:
Gotta love it when interviewers try to get too damn clever for their own
good. Such a detail shouldn't even really matter in production code
anyway. It's a trivia question.

I'm not sure it is trivia. People read the following and may be mislead:

Class::Class(void):
A(0), B(A+1)
{
}

PC-lint warns if variables are not initialised or are not initialised in the
order of declaration.
 
T

Triple-DES

I'm not sure it is trivia.  People read the following and may be mislead:

Class::Class(void):
    A(0), B(A+1)
{

}

or, for that matter:

Class::Class() :
B(A+1), A(0)
{
}

assuming
struct Class
{
Class();
private:
int A;
int B;
};
PC-lint warns if variables are not initialised or are not initialised in the
order of declaration.

So does gcc. Unfortunately, it also warns for classes.
 
A

Alan Woodland

Can we have Puzzle thread here?? If any one has a interesting C++
question which helps to understand c++ better or makes interview
easier to face can post here..

What does this output?

#include <iostream>
#include <string>

int main() {
const std::string msg = "Hello puzzled world!";
const std::string::size_type l = msg.length();
for (int i=0; i<l;) { // Is this what it seems ????/
std::cout << i++[msg.c_str()] << std::endl;
}

return 0;
}

Note: My compiler actually by default disables the thing that makes this
behave unexpectedly, and merely emits a warning that it is ignoring it.
Not sure if that's non-conforming behaviour or not?

Alan
 
A

Alan Woodland

Pete said:
#include <iostream>
#include <string>

int main() {
const std::string msg = "Hello puzzled world!";
const std::string::size_type l = msg.length();
for (int i=0; i<l;) { // Is this what it seems ????/
std::cout << i++[msg.c_str()] << std::endl;
}

return 0;
}

Note: My compiler actually by default disables the thing that makes this
behave unexpectedly, and merely emits a warning that it is ignoring it.
Not sure if that's non-conforming behaviour or not?

The meaning of a is defined as *(a+b). If the latter is valid, a
compiler that complains about the former is enforcing style guidelines,
not language requirements.


The a wasn't what my compiler was complaining about here, it was a
distraction from the real problem!

When I tried it with g++ -trigraphs (and on another much older compiler
which doesn't disable trigraphs by default) it results in an infinite
loop! The comment on the line where the for-loop starts includes the
sequence ??/ which is actually a trigraph representation of \, meaning
the next line is a continuation of the previous one, and thus part of
the comment still, so there is nothing in the loop body!

Alan
 
T

Triple-DES

The a wasn't what my compiler was complaining about here, it was a
distraction from the real problem!

When I tried it with g++ -trigraphs (and on another much older compiler
which doesn't disable trigraphs by default) it results in an infinite
loop! The comment on the line where the for-loop starts includes the
sequence ??/ which is actually a trigraph representation of \, meaning
the next line is a continuation of the previous one, and thus part of
the comment still, so there is nothing in the loop body!


Nice red herring :)
 

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

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top