|
A binary file is a file that contains bits. Every 32 bits make a number (several digits/symbols with no space between them) or a word. A number can then be transformed and become an integer (several digits/symbols) or a char (just one symbol). Character set (Unicode for example) has to do with how a word of bits becomes a char. Is that how it works?
[edit] A text file is an inefficient way to store numbers because each digit is one char
modified 26-Aug-24 9:00am.
|
|
|
|
|
Calin Negru wrote: Is that how it works?
yes, more or less.
Every file is just a series of bits.
It's up to the user (programmer) to interpret how the series of bits is converted to something practical (text, numbers, ... )
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
Generally speaking, all files contain bytes. What interpretation you put on those bytes is up to you. A file containing the hex bytes 61 62 63 64 (without spaces ) might be interpreted as a 32 bit integer of value 1684234849 (assuming little endian byte ordering) or the 4 characters abcd. Interpretation is everything.
Text files may be slower than binary files to read/write, but they do have the advantage of being processor agnostic. For example in 32 bit mode, structs have different padding on ARM and x86, so given
struct S {
}; If you have a data file containing an array of struct S , you can't just copy the data file from an x86-32bit system to an ARM-32bit system and assume that the offsets for the member is going to match. That's also true for x86-32 to x86-64. Even if the struct members don't have different sizes (e.g. a long may have 32 bits or 64 bits), they may have different padding requirements between 32 and 64 bit systems.
Then there's the whole little endian vs big endian situation.
But a text file can be read by any system, without any conversion routines.
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
|
|
|
|
|
A binary file is a stream of bits that can be interpreted by your code in any way it wants. 32 bits does NOT mean it's a number. Those exact same 32 bits can be four ASCII characters, two 16-bit UTF-16 characters, four bytes, two short integers, either signed or unsigned, or one signed or unsigned integer, or 32 Booleans encoded into 4 bytes, or ...
Bytes in a file represent nothing until the code that reads the file assigns meaning to them.
Text file are just streams of bytes, just like all files are. Efficiency is subjective.
|
|
|
|
|
Thanks for your feedback. I think I understand.
|
|
|
|
|
I`m trying to place a derived class object into an c++ array containing base class objects. You suggested I should use the following
unit* LUnits = new unit[2];
soldier * S = new soldier();
LUnits[0] = dynamic_cast<unit*>(S);
sailor* AB = new sailor();
LUnits[1] = dynamic_cast<unit*>(AB);
sailor* tar = dynamic_cast<sailor*>(LUnits[1]);
The code above doesn`t compile with VS2022.
This compiles:
sailor* tar = dynamic_cast<sailor*>(&LUnits[1]);
I can't find a solution for the following
LUnits[0] = dynamic_cast<unit*>(S);
The compiler doesn't recognize the = operator. The errors are E0349 no operator "=" matches these operands and
Error C2679 binary '=': no operator found which takes a right-hand operand of type 'unit *' (or there is no acceptable conversion)
Any ideas how to move forward?
modified 24-Aug-24 6:31am.
|
|
|
|
|
I think you are missing an indirection level:
unit* LUnits = new unit[2];
Lunis is a normal array. Elements are unit objects
LUnits[0] = dynamic_cast<unit*>(S);
This fails because LUnits[0] is a unit , not a unit*
The first line should be:
unit** LUnits = new unit*[2];
Mircea
modified 23-Aug-24 13:45pm.
|
|
|
|
|
unit* LUnits = new units[2] creates an array of 2 unit , not an array of 2 pointers to unit.
You probably want a double dereference:
unit** LUnits = new units*[2]; soldier* S = new soldier;
unit[0] = S;
It feels like there should be a better way to do that.
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
modified 23-Aug-24 13:54pm.
|
|
|
|
|
Thank you guys indirection was the problem
modified 23-Aug-24 16:56pm.
|
|
|
|
|
I am adding a new object to an existing object.
In QtCreator, I have an option to add it /pass it as a class new parameter.
The other option is to add new object as a .so library.
I am asking for (academic) evaluation / discussion of each option,
as a C++ task , nothing to do with Qt.
I will appreciate your time , however, off subject ,
immature flaming responses will be as always ignored.
Cheers
|
|
|
|
|
Sorry, I must be hard of thinking, but your question doesn't make much sense to me. By "adding an object to a class" I think in terms of
class C1 {
int i;
double d;
public:
C1(int x, double y) : i(x), d(y) {}
...
};
class C2 {
int i;
double d;
std::string str; public:
C2(int x, double y, std::string s) : i(x), d(y), str(s){}
...
};
If that's the case, then you've got a couple of choices. If you've got full control of the source, including the definition and implementation of the class, then it might make sense to just add the object to the original class and recompile. That might be the way to go especially if this is a stand-alone app with no, or few, clients depending on it.
Alternatively, create a derived class e.g.
class C1 {
int i;
double d;
public:
C1(int x, double y) : i(x), d(y) {}
...
};
class C2 : public C1 {
std::string str; public:
C2(int x, double y, std::string z) :
C1(x, y), str(z) {}
}; With a derived class, there's no breakage for anything that's using a C1 . Anything that needs an "improved" C2 has the functionality required. Additionally, anything that expects a C1 can take a C2, but you do not have access to C2's extended functionalit.
If you mean something different, maybe you can create a (short) example of what you're trying to accomplish?
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
|
|
|
|
|
Thank you.
I am not that versatile to create derived class - but that is something I like to try.
I am pretty stuck with Qt and not sure how to physically accomplish the derivation.
At present I am testing the "add" using a library, mainly because
the library was tested long time ago.
|
|
|
|
|
Googling for something like "C++ derived class tutorial" should give you some useful hits.
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
|
|
|
|
|
jana_hus wrote: immature flaming responses will be as always ignored. as will yours.
|
|
|
|
|
Good afternoon,
a bit stumped with this one - any help would be greatly appreciated:
System.Void, System.Object, System.Inptr not defined or imported... a little bit stumped with this one... any help would be greatly be appreciated...
Regards,
Pieter Claassens
|
|
|
|
|
I think this is C#, not C++. C++ has no "Object" class, but it does have various integer types.
|
|
|
|
|
Without some context, it's almost impossible to figure out what you may be doing wrong.
Additionally, this looks like C#, not C++, so maybe in the wrong forum?
"A little song, a little dance, a little seltzer down your pants"
Chuckles the clown
|
|
|
|
|
Apologies - this is a c# question ...
|
|
|
|
|
I have been searching for hours and i am having a really hard time finding any reference lists of theese legacy methods.
Basically what i am looking for is initializing graphics in DOS aka Dosbox or DOS boot disk for bootup.
I am looking for:
* BIOS registers for graphics modes and other useful things
* Methods to incorporate these registers in C with methods aka inline assembler
Please GOD make information about programming short and on point! Amen!
|
|
|
|
|
Alex D Aug2024 wrote: * BIOS registers for graphics modes and other useful things
Googling with the following seemed to return useful information
"BIOS" "graphics modes" PC-dos
Alex D Aug2024 wrote: Methods to incorporate these registers in C with methods aka inline assembler
Been a while but rather certain there was no remapping in the address space in 16 bit dos. Don't even think it was possible. Although perhaps 286/386 allowed that.
If it wasn't then you certainly did not need inline assembly. Because an address with, for example 0x10 was just a matter of initializing a pointer with exactly that address. Make sure it is a byte pointer.
|
|
|
|
|
Don't use the word "register". It doesn't apply in this case.
Search for "BIOS and DOS interrupts" and you'll find what you're looking for.
|
|
|
|
|
Let’s say I’m adding a derived class object to a vector that holds objects of base class type. STL vector allows me to do that without any explicit conversion. How do I revert the object inside a vector back to the derived class type? I’m only adding a pointer to the container not the actual object.
modified 12-Aug-24 10:26am.
|
|
|
|
|
|
So it works the same way. Got it.
|
|
|
|
|
Let me expand a bit on my previous answer[^].
As I said, you can convert a pointer (or reference) to pointer (or reference) to the base class. This called "upcasting" because you are moving "up" in the inheritance tree. The conversion is "non-destructive", in other words you can later on "downcast" (move from base to derived) as long as you know what type of object was in the first place. An example:
struct Unit {
Unit (int tag) : dog_tag(tag){};
virtual std::string kind () = 0;
int dog_tag;
};
struct Soldier : public Unit {
Soldier (int tag) : Unit(tag) {};
virtual std::string kind() {return "soldier";};
float running_speed;
}
struct Sailor : public Unit {
Sailor (int tag) : Unit(tag) {};
virtual std::string kind() {return "sailor";}
int life_jackets;
};
std::vector<Unit*> actors {new Soldier(555), new Sailor(666);};
int main () {
Unit* u0 = actors[0];
std::cout << "Actor 0 is a " << u0.kind() " with tag " << u0.dog_tag << std::endl;
If you would look with a debugger at u0 you would see a memory layout something like this:
-------- ------------------------------
u0| 0x1234 |------->| pointer to vtable of Soldier |
-------- |------------------------------|
| dog_tag |
| -----------------------------|
| running_speed |
------------------------------
You can see now why the code works: no matter what kind of object you deal with, the first part of the memory layout is the same. Compiler simply ignores whatever is after the dog_tag field.
A few more lines of code (please ignore that I didn't initialize other fields):
Soldier *s = (Soldier *)u0;
std::cout << "Running speed " << s->running_speed << std::endl; s has exactly the same value as u0 but compiler considers it a pointer to a Soldier object so it uses the value from the running_speed field. I could have written:
Sailor *ss = (Sailor*)u0;
std::cout << "Sailor has " << ss->life_jackets << " life jackets"; And compiler wouldn't have cared at all. It would have accessed the memory at life_jackets location as an integer and this is that.
Now, what happens if I use dynamic_cast instead of C-style casts?
Sailor *ss = dynamic_cast<Sailor*>(u0) The generated code would have used the value stored in the vtable member to check if the 0x1234 truly is a Sailor object. As the vtable value doesn't match the address of vtable for Sailor objects, the dynamic cast operation would have returned a NULL pointer.
Things to remember from this story:
- upcast is always safe. Downcast not so much.
- dynamic_cast is safer than C-style cast provided you check the result.
- dynamic_cast works only for classes that have at least one virtual function. If your object doesn't have a virtual table compiler cannot figure out what type of object it really is.
Mircea
|
|
|
|