News:

Do you need help?
Simutrans Wiki Manual can help you to play and extend Simutrans. In 9 languages.

code::blocks

Started by Roads, September 24, 2012, 03:51:48 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Markohs

good, if you have any question you'd like to ask, don't hesetiate to do it, I think teaching is my frustrated prefession. :)

isidoro

Quote from: Markohs on September 29, 2012, 05:33:20 PM
[...] I think teaching is my frustrated prefession. :)

I don't imagine you that old...  Never too late.  Give it a try.   ;)

@Roads:  one small detail: signed int is just the same as int.  In fact, if you don't have a special reason to use unsigned int, I would advise you to always use just int...

Roads

Markohs, you may not teach professionally and if not, then that profession is missing out on a good one!  Isidoro gives good advice. :)


I'm going to take you up on your offer to help whenever I have a question, I'm sure I'll have plenty in the future but will try not to abuse that offer.


Isidoro, thank you.  It is things like that you hardly ever get from tutorials.

Roads

#38
This is a tutorial example program:




// increaser
#include <iostream>
using namespace std;


void increase (void* data, int psize)
{
  if ( psize == sizeof(char) )
  { char* pchar; pchar=(char*)data; ++(*pchar); }
  else if (psize == sizeof(int) )
  { int* pint; pint=(int*)data; ++(*pint); }
}


int main ()
{
  char a = 'x';
  int b = 1602;
  increase (&a,sizeof(a));
  increase (&b,sizeof(b));
  cout << a << ", " << b << endl;
  return 0;
}



There are several things about as clear as mud to me on this but I need to back track on one of them.  Why is this 'x' declared as a constant?  Wouldn't it have been just as good to declare it as "x"?


Combuijs

What a horrible programming style for a tutorial...  :police:

'x' is a character
"x" is a character array (string) of length 1. (actually it takes two characters: x and a terminating '\0' character, but lets not get into detail here...).
Bob Marley: No woman, no cry

Programmer: No user, no bugs



Markohs

Quote from: isidoro on September 29, 2012, 11:39:48 PM
I don't imagine you that old...  Never too late.  Give it a try.   ;)

hehe, no, I'm *just* 34. :)

Mmmm... Yea, thought about it sometimes, I'll try someday. The few times I've done it I've feelt good. :)

Markohs

#41
Yep, as Cumbuijs stated "x" is an array of characters and 'x' is just one character, one byte.

If you try to compile this:


char x = 'hi';


You will get warnings in compiler


1>c:\users\marcos\documents\visual studio 2010\projects\ttttt\ttttt\ttttt.cpp(10): warning C4305: 'initializing' : truncation from 'int' to 'char'
1>c:\users\marcos\documents\visual studio 2010\projects\ttttt\ttttt\ttttt.cpp(10): warning C4309: 'initializing' : truncation of constant value


That's I think because 'hi' it's interpreted as a integer since it's 2 bytes, one for each character : 0x6869. A int in C is 16-bit by definition. The equivalent, "hi" whould be 3 bytes since it whould be 0x686900, since strings are allways terminated with a 0 byte.

About constants: When you express "hi", the compiler allocates 3 bytes on the memory, just 3. If you later try to write into that buffer let's say 5 bytes, you'd be writing out of bounds of the allocated memory, and unpredictable results will appear. When you declare the variable as const, you make sure the compiler forbids a re-write in that variable, so safer code. But there are many ways of writing to it anyway, as you saw on that example-

Look it that way, when you declare a variable as "const", you make sure you don't write accidentally over it across your code, and you give a hint to the compiler that that variable will never change, so he can optimize the resulting code in certain ways that's hard to explain easily. :)

In the example, 'x' results in that in the binary,  there is one byte of memory, a read-only one that gets allocated with the initial value of 0x78 , that's the ascii code for "x". You'll notice that in C/C++ you can do all kinds of weird stuff, and later in that example they over-write that value. That's not suposed to happen, really.

The default type of 'x' is const char, but it's assigned to a char, later a pointer to it it's passed as (void *), and manipulated in the other function. Weird stuff, but it's designed I guess to show you what kind of "tricks" pointers allow you to use. pointers are very very useful, and the base of any serious C++ program, but are hard to understand fully, and really dangerous. Specially the "(void *)" cast that's the ultimate trick that allows you to manipulate ANYTHING ANYHOW.

Roads

@Combuijs


I had read all this stuff and kinda, sorta, understood it.  You made it really clear in one sentence.  Thank you!


@Markohs


I like this idea of the compiler protecting you from over writing constants.  I can see where that could happen.  I guess you could over write with something with the same number of bytes if I'm understanding this correctly but still it's a good thing.


It looks like about anything can be done with C++.  It sure is a long way from FoxPro and Oracle.


About the void pointer...I think I'm going to put that on the back burner and move on.  I'll come back to it in the future if need be.


It is really very kind of both of you to take the time to do this.  I hope others on the message board are reading this and learning something from it too.

Markohs

#43
Quote from: Roads on October 05, 2012, 12:16:08 PM
It looks like about anything can be done with C++.  It sure is a long way from FoxPro and Oracle.

Yeah, it's a language very close to hardware, that has it's advantages and disadvantages. It's speed light fast, has not much restrictions but in exchange you have to control lots of things manually, and are continually exposed to corrupt memory if you don't know exactly what are you doing.

It's like a swiss knife, useful for everything, reliable, versatile, simple, but... Whould you peel an elephant with a swiss knife? Prolly not a good idea... But you can do anything you want. )

It's hard to master and very prone to programming bugs, anyway this year it recovered #1 rank in most used languages in the world, C alone. If we sum C and C++ programs they almost double the number of java programs written nowadays. You can see it here:

http://langpop.com/

Ters

In C++, void pointers are useful for two things: interfacing with (legacy) C code and as a gateway to black magic. C++ also has better and safer ways to cast, though their verboseness makes them longer to write. (And for an example to combine so C-ish stuff like void pointer casting with streams, that is perhaps the most un-C-ish thing in all of C++.)

Roads

This kept nagging at me in the back of my mind while I was learning and doing other things.  Why did they use the word char and int when declaring pchar and pint as void pointers?  Couldn't they just have used the word void instead?  The reason I'm asking is if a void pointer can point to any data type, why declare them as char and int?

Hope my question makes sense.

Ters

I'm not quite sure what you meant in your second sentence, but you should use char * instead of  void * so you know what data type it is. It's called type safety. Otherwise, you may pass a pointer to an char to something expecting an int.

Roads

Thanks Ters.  Let me see if I got this.  Since a void pointer can point to any data type, then you could use void instead of char or int?  It is purely a convention or safety thing?

Markohs

It's because as void * you don't know the size of the data, so the compiler forbids you to use any indirection to access its contents until you cast it back to a known data pointer.

Try to compile this code to ilutstrate your doubt, and check what the compiler has to tell you:


int main(){

   char c = 'd';
   int i = 10;

   void *vp;

   vp = &c;

   *vp++;

   vp = &i;

   *vp++;

}


Markohs

If you try this:

#include <stdio.h>

int main(){

   char c = 'd';
   int i = 10;

   void *vp;

   vp = &c;

   char *cp;

   cp = vp;

   *cp++;

   vp = &i;

   int * ip;

   ip = vp;

   *p++;

}



it won't compile either, for a different reason(try it), and finally, this will compile:


#include <stdio.h>

int main(){

   char c = 'd';
   int i = 10;

   void *vp;

   vp = &c;

   char *cp;

   cp =  (char *) vp;

   *cp++;

   vp = &i;

   int * ip;

   ip = (int *) vp;

   *ip++;

}





Roads

C++ forbids incrementing a pointer of type void.

Okay, I think I've got it now.  As always, many thanks!


Modify:  You've added some stuff while I was posting.  I'll check it all out.  That first example and explanation was really good.

Markohs

Yea, to amke it short a pointer are (most of the times, and nowadays) just a 32 or 64-bit number representing one point of the memory. A void* is just that, a number, but you don't know what are you pointing at, it can be anything, a int, a char, a struct, a union,a object... You need to cast it to something so the compiler knows what are you pointing at, before manipulating it.

Roads

Well, I'm going to have to do a lot more thinking on this.  At first it looked like your second example should compile...it's pretty vague in my mind but I'm beginning to understand.  Doubt I would have ever figured this out without your help.

Ters

Simple rule: DON'T use void* unless you KNOW what you're doing. With void pointers, you're basically all the way down at the hardware level where everything is just bits of random data.

Some library functions accept void*, but they also ask for the size of the data and are made to operate on all kinds of data, and were written by people who (mostly) knew what they were doing. malloc also returns void pointer, but you're supposed to cast it to a pointer of the right type immediately. It is however the C way. The C++ library usually use templates, or some other C++ feature, instead (though sometimes just as a wrapper).

Markohs

If you are feeling overhelmed with C pointers you are in the right way, this **** is not easy to understand. Now you are learning.

To show us your grattitude Roads, I'd ask you to get us the brunette on the left of this video:

http://www.youtube.com/watch?v=vDRnkTSdbRE

I'd be happy just with that. ;)

Ters

As a warning, this was just pointers to data. There is also pointers to functions, which aren't any different if you think like a computer, but the type of these pointers are long to write. And in C++ there is also pointers to member functions, which inexperienced humans seem to have a hard time understanding why are different from regular function pointers, but they are very different from the point of view of the computer.

Roads

QuoteTo show us your gratitude Roads, I'd ask you to get us the brunette on the left of this video:


Picky. :)


If any of the three of them said, "hey old man, you wanna come play with me?"  I'd be like, anytime, anywhere, any place.


Guys, unless this void pointer is used in Simutrans, I seriously doubt I'll ever use it.  It's not like I'm going to give up retirement and look for a job. I like sleeping in and playing way too much.

Markohs


Ters

There are probably void pointers in Simutrans, as there is quite some low level stuff in there. There's even assembly code in Simutrans. Custom stuff to get things running as fast as possible. That kind of code is not suited for someone just starting to learn C++ (I'm not sure what knowledge you have in computer science), nor is it the kind of code one would write unless necessary.

isidoro

Quote from: Roads on October 14, 2012, 12:20:49 PM
C++ forbids incrementing a pointer of type void.
[...]

Not only it forbids it, it also makes no sense.  I'll explain it:  a pointer is a variable that holds a memory address.  For instance:

  int a; // An integer variable
  int *ip; // A pointer...
  ip=&a;   // ...that holds the address where a is stored


So, for instance, ip may hold the address 1024, where the data of a is located.

If I do: ip++; what is the address that is now in ip?

One is tempted to say the following address.  But that is wrong.  An integer in my machine needs 4 consecutive memory locations to be stored.  In this case, ip will point to the next integer, i.e., four positions ahead: 1024+4=1028.

Finally, if we have a void *, how many positions will the compiler advance?  It doesn't know...  That's the reason it is forbidden.

So a pointer is a memory address (a location if you want) and a surname, indicating what lays there.

Roads

Isidoro, when I began reading your post I was thinking, "I understand this stuff and it has been said, why is he saying it again?"  Then I got to the part about the following address.  I thought it would be 1025.  Thank you very much for explaining that.

Ters, what you said is good to know.  Hopefully the few things I want to do eventually will not involve void pointers and if it does no doubt I'll be posting my code if it is not too long asking y'all to take a look at it.

Ters

Another thing. Though pointers come technically unchanged from C, in C++ a pointer is a type of iterator, a concept that doesn't exist in C. This is-a relationship is no in a sense of class inheritance, but conceptually. There are other iterators that aren't pointers, but classes, usually one or two types associated with each container. Iterators can be used for moving forwards through a collection of items (by incrementing the iterator: ++iterator), getting the item at the current position (dereferencing it: item = *iterator), possibly moving backwards (by decrementing it: --iterator), and possibly skipping several items (by addition or subtraction: iterator += 7).

What an iterator can do depends on what kind of iterator it is, progressing for very simple iterators to more capable ones. Pointers are of the most capable kind, where you can move in both directions and skip several items in one go. The C++ library contains many utility functions and classes that accept certain kinds of iterators, of which pointers is a match.

Many other programming languages also have iterators, but while still used for moving through collections, I have not seen anyone behave like C++ iterators. Most languages don't have pointers either, just something similar called references. C++ also has this pointer-like thing called references, but having pointers, the references in C++ are a bit more special than references in languages like Java (but more like those in Fortran).

Roads

Ters, this is way beyond me now but I do appreciate the time you took to write and will likely be referring back to it at some point.  I've got this thread on my permanent links list.

You mentioned earlier you didn't know the extent of my programming knowledge.  I guess it would be kind of unusual nowadays but was pretty common when computers first became popular.  Lots of people like me bought a computer or else had access to one at work and learned Dbase.  From that some of us graduated to FoxPro and a few later on to Oracle.  At the time I worked for a large maintenance facility doing all kinds of inspection and testing work - ultrasound, mag particle, welding, coatings...

At the time the shops did everything the old fashioned way with pen and paper.  We kept the calibrated equipment due dates listed on a white board.  Time sheets were filled out by the foreman and sent to payroll.  Even the shop orders were kept in a binder.  I began writing applications to replace all that and quite a bit more stuff.  By the time I retired it was all done on the computer.  So my experience as far as low level programming is nil but as far as making use of a high level language it is extensive.

Markohs

Simutrans coding style recomends not using void pointers.

From documentation/coding_styles.txt

Quote
- Avoid void * if possible. This is especially dangerous when used for
  pointers to objects, because the compiler can't call the destructor of the
  object through a void pointer. Also all type checks are impossible on
  void *. Use of void* is tolerated in C code, but not in C++ code.
  -> try using templates instead of void pointers.

prissi

The most use of void simutrans does is when it uses the memory allocation in freelist. If you want to look at some pointer code, you could lok at dataobj/freelist.cc . But there are certainly more rewarding places to study.

Roads

Prissi, You can believe I will take your advice and only be looking at the more rewarding places. :)

I only wanted a basic understanding since it was covered in the tutorial and now I'm wondering why the author even bothered doing it and doing it half **** at that.

Roads

#66
This is the intro statement of an example tutorial:

QuoteHere you have an example that overloads the addition operator (+). We are going to create a class to store bidimensional vectors and then we are going to add two of them: a(3,1) and b(1,2). The addition of two bidimensional vectors is an operation as simple as adding the two x coordinates to obtain the resulting x coordinate and adding the two y coordinates to obtain the resulting y. In this case the result will be (3+1,1+2) = (4,3).

and here is the program:



1  // vectors: overloading operators example
2  #include <iostream>
3  using namespace std;
4
5  class CVector {
6  public:
7     int x,y;
8     CVector () {};
9     CVector (int,int);
10    CVector operator + (CVector);
11  };
12
13  CVector::CVector (int a, int b) {
14   x = a;
15   y = b;
16  }
17
18  CVector CVector::operator+ (CVector param) {
19  CVector temp;
20  temp.x = x + param.x;
21  temp.y = y + param.y;
22  return (temp);
23  }
24
25  int main () {
26    CVector a (3,1);
27    CVector b (1,2);
28    CVector c;
29    c = a + b;
30    cout << c.x << "," << c.y;
31    return 0;
32  }


Actually I sort of understand most of the program but one thing I don't have a clue about is "param."
If anyone can shed some light on this or say anything about the program it would help me greatly as even the things I understand I only vaguely understand...


Modify:  added line numbers

Ters

param is just the name for the parameter to the method called operator +, just like x is in f(x) = x+x.

When the compiler encounters the following program

Foo a, b, c;
a = b + c;

it will see if the second line can be transformed to

a = f(b, c);

to match some existing function f(x, y), or

a = b.f(c);

to match a method f(y) in class Foo except that the function or method isn't called f, but operator +.

Roads

Thank you, Ters

I'm sure I do not understand all you said but it is certainly helpful.

Let's see if I'm anywhere in the ball park or just wandering around trying to find the park.  It looks like in line 19, "temp" is declared as an object of CVector.  Then this function called "operator+" is accepting the values of "x" and "y" which in the first instance would be 3 and 1, and adding them because that is how the operation is declared for the class?

isidoro

In fact, it is quite simple.  As Ters pointed out, when you have:

26    CVector a (3,1);
27    CVector b (1,2);
28    CVector c;
29    c = a + b;

the last line is equivalent to:

29    c = a.operator+(b);

if that were legal in C++.  You just have to imagine that operator+ is just a funny name for a method in CVector.

Once you think that operator+ is just another method, all you are doing is calling it.  Variable param gets a copy of variable b, and variables x and y are just those properties of variable a.  Variable temp is only a placeholder where to build the return value before actually returning it.

By the way, return is not a function and, thus, the parenthesis can be dropped in line 22.  A matter of style...  8)