Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 19 Aug 2002
Offline Last Active Yesterday, 08:56 PM

Posts I've Made

In Topic: FizzBuzz: Enterprise Edition!

29 April 2016 - 06:30 PM


I can't. stop. laughing!

In Topic: linked list of struct that is derived from another c++

29 April 2016 - 02:24 PM

You could CRTP it (let's see if I even remember how to do this in C++):
template<typename T>
struct LinkedListNode
    LinkedListNode *prev;
    LinkedListNode *next;

struct structure1 : public LinkedListNode<structure1>
    char *name;
    // etc
Though to be honest I haven't used C++ in over a decade and this might be a frowned-upon solution. If I screwed this up, someone be sure to let me know!

As far as your linked-list-of-linked-lists goes, you would need to follow all of the structure3 next links to the end, and then take the structure1 links from it to the end separately:
structure1 *getLastEvent(structure3 *first_object)
    if (first_object == nullptr)
        return nullptr;

    structure3 *s3 = first_object;

    while (s3->next != nullptr)
        s3 = s3->next;

    structure1 *s1 = s3->First_linked_list;

    if (s1 == nullptr)
        return nullptr;

    while (s1->next != nullptr)
        s1 = s1->next;
    return s1;

In Topic: I Have a Problem in "char *" & "LPCWSTR"

28 April 2016 - 06:47 PM

The W in LPCWSTR stands for "Wide" and usually if you see errors about that it means you're mixing Unicode and Multibyte strings in your program due to incorrect settings or incorrect string literals.

You can either try making everything consistently Unicode (put L prefixes on all of your string literals or the _T macro like you've already tried) or consistently Multibyte (open your project properties and change "Character Set" to "Use Multibyte Character Set".

If that doesn't help then the problem is much deeper and you might need to post more code.

New VS2015 C++ windows projects default to Unicode, I believe. Older tutorials like NeHe probably assume the older multibyte default.

In Topic: Network Library that supporst RPCs

28 April 2016 - 04:32 PM

For most types, the sender and receivers both know how big they are based on agreed-upon information. You typically do NOT need to send the size of every field.

For example, you could write code that agrees that all 32-bit integers are 4 bytes. Or you could agree to write them using SQLite4 varint encoding, or VLQ encoding, or whatever.

Let's look at a bare-bones BinaryReader/BinaryWriter pair in C#:
public class Foo
    public int A;
    public int B;

    public void Read(BinaryReader reader)
        A = reader.ReadInt32();
        B = reader.ReadInt32();

    public void Write(BinaryWriter writer)
The Read and Write functions don't need to write bytes indicating that A is 4 bytes and B is 4 bytes, because it's implicit.

You only really need lengths for two main things:

1. Knowing how much data to wait for in your network receiver before you attempt to deserialize the whole message.
2. Skipping fields of unknown types if you have a protocol that allows for different client versions to talk to each other. You probably won't need this, though.

For RPC, you could do something like this (very barebones example):
public void HandleRPC(BinaryReader reader)
    var function = (RPCFunction)reader.ReadInt32(); // RPCFunction being an enum

    switch (function)
        case RPCFunction.ConsoleWriteLine:
            // This is a bit of a security risk if you were to do this in C++, but in C# the worst you'll get is an exception.
            var formatString = reader.ReadString(); // Internally it has the string length first
            var numArgs = reader.ReadInt32();
            object[] args = new object[numArgs];
            for (int i=0; i<numArgs; ++i)
                args[i] = ReadPolymorphicType(reader);
            Console.WriteLine(formatString, args);

        // Other functions read their expected parameters, then call the appropriate function in the same way.

public object ReadPolymorphicType(BinaryReader reader)
    int typeId = reader.ReadInt32();
    switch (typeId)
        case 0: return null;
        case 1: return reader.ReadByte();
        case 2: return reader.ReadInt32();
        case 3: return reader.ReadSingle();
        case 4: return reader.ReadDouble();
        case 5: return reader.ReadString();
        case 6: { var foo = new Foo(); foo.Read(reader); return foo; }
        // etc.
This is a manually-written, tedious way to go about it, but it serves as an example for how you can serialize/deserialize data. You would ideally want to use whatever is most convenient for your project.

I would personally use varints for all integers, have string backreference support, etc.

In Topic: Network Library that supporst RPCs

28 April 2016 - 11:14 AM

Definitely put the size first. It's so much easier than worrying about delimiters, EOM indicators and dealing with escaping other data somehow.

Really the only nuisance part of doing size first is you have to build up your whole message in a temporary buffer first, then measure its length immediately before sending. But that's not nearly as bad as dealing with escaping data (which inevitably leads to bugs).

If you use a binary format you don't have to worry about any kind of string escaping or delimiters. Your data is arranged in consistent blocks with the leading information letting you know exactly how much data comes next, either using lengths, or type IDs, or any other deterministic approach.