News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Why does the second string output produce garbage?

Started by bugthis, July 08, 2024, 11:29:54 AM

Previous topic - Next topic

bugthis

Quote from: zedd151 on July 09, 2024, 03:10:39 AM
Quote from: bugthis on July 09, 2024, 12:49:22 AMSo, no, not every string requires a terminator.
Since there is one terminator, everything before it is considered to be part of the same string - no matter whether or not you declare each part of the string with its own variable as you have done.

True you may print any portion of the string (from a given "variable" address to terminator) that has a variable name as in your example but it will always rely on the fact that a terminator is present.

 :rolleyes:
As i said before, this is an old trick from old programmers the kids seem not to understand here.

A string is not defined by a terminator, but a string is simple a sequence of characters assigned to a variable and accessible by the variable. Therefore, subsequent strings are not counted as part of the first string.
A terminator is required for the output and it's absolutely okay to have that terminator in another following string as long as the previous string and what you want to output are before it.

It's an old programming trick because it saves some bytes.
For example, you can do the following.

.data
question DB "Say yes or no?"
endl DB 13, 10, "$"
yes DB "You said: yes.$"
no DB "You said: no.$"

.code
ASKQ:
mov ah,9
mov dx,OFFSET question ; output will end, thanks to the following endl string sequence. 1-3 bytes are saved.

...; some code that does the input, compare and branching (conditional jump)

no:
mov ah,9
mov dx,OFFSET endl ; We want one more line of space.
int 21h
mov dx,OFFSET no
int 21h
mov ah,9
mov dx,OFFSET endl ; reusing endl again, so we have CRLN
int 21h
jmp ASKQ

yes:
mov ah,9
mov dx,OFFSET endl ; We want one more line of space.
int 21h
mov ah,9
mov dx,OFFSET yes
int 21h
mov dx,OFFSET endl ; reusing endl again, so we have CRLN
int 21h

...; some code to end program

And by the way, yes, this trick is from an old assembly language programming book from a time when RAM was expensive and in short supply. So I'm not going to argue with kids about it. Everything has been already said about it. Just terminate every string if you think you have to do it that way. But then you might as well just use C. Because then you don't need the power of assembly language anyway.


NoCforMe

Quote from: bugthis on July 09, 2024, 04:09:01 AMYou obviously didn't understand what i wrote.
I did. You were just wrong in what you stated.
Assembly language programming should be fun. That's why I do it.

sinsi

Quote from: bugthis on July 09, 2024, 04:34:42 AMAs i said before, this is an old trick from old programmers the kids seem not to understand here.
Insults work so well here  :badgrin:

There seems to be one person here who doesn't understand things here.

bugthis

Quote from: sinsi on July 09, 2024, 07:13:04 AMThere seems to be one person here who doesn't understand things here.

I know at least one person here whose definition of strings is wrong and who thinks they must be all like C-strings.

Even in the C programming language, one regrets that a terminator character was used when defining C strings instead of simply defining the length of the C string, for example, in the first element.

Some reading:

https://queue.acm.org/detail.cfm?id=2010365

https://www.reddit.com/r/programming/comments/j6s62/the_most_expensive_onebyte_mistake_did_ken_dennis/?rdt=52626


NoCforMe

Quote from: bugthis on July 09, 2024, 07:54:55 AM
Quote from: sinsi on July 09, 2024, 07:13:04 AMThere seems to be one person here who doesn't understand things here.

I know at least one person here whose definition of strings is wrong and who thinks they must be all like C-strings.
Dunno if you're referring to me, but yes: apart from Pascal-type strings to which you refer (where the first element is the length of the string), all strings must "be like C strings" in that they must have a terminator. A NULL terminator in most cases, a '$' in the case of DOS, as in your code. Otherwise we all know what happens when you try to display a terminator-less string ...

Oh, sure, you can define a "string" internally in your code any way you like, but if you're going to use standard functions with it, Win32, Unix or DOS, it had better have a terminator!**

Your bringing up your "trick" (which is trivial and which anyone who ever wrote DOS assembly-language programs, as I did back in the day, was familiar with) doesn't change that. At some point in the string, there needs to be a terminator.

Now, have you fixed your problem with your code yet?

** With certain exceptions, like ExtTextOut() which requires the length of the string as one of its parameters.
Assembly language programming should be fun. That's why I do it.

sinsi

A string is a list of bytes. A computer needs a limit which can be either a terminator (any byte, as long as it is consistent) or a length. Most Windows functions require C type strings (null terminated) but a function like WriteConsole requires a length. Windows also uses Unicode strings in kernel functions that is a counted string (UNICODE_STRING structure) which may or may not be null-terminated.

NoCforMe

Quote from: bugthis on July 09, 2024, 07:54:55 AMEven in the C programming language, one regrets that a terminator character was used when defining C strings instead of simply defining the length of the C string, for example, in the first element.

Well, since you brought this up, yes, there was some controversy over the way strings should be structured in the dim, dark past, but that has pretty much been resolved in favor of terminated strings.

And I for one am glad that our overlords and masters decided on that. As an assembly-language programmer, can you imagine the nightmare of having to deal with the alternative? (In a higher-level language, it would be six of one or half a dozen of the other from the programmer's point of view.)

Instead of simply defining a string thus
SomeString  DB "ThIs ArE a StRiNg????", 0

you'd have to write a macro to define a string, which would insert the length element before the text. And you'd have to deal with that intrusive element every time you did anything with the string. So no regret here that we didn't go the other way.
Assembly language programming should be fun. That's why I do it.

bugthis

Quote from: NoCforMe on July 09, 2024, 08:03:11 AM... apart from Pascal-type strings to which you refer (where the first element is the length of the string), all strings must "be like C strings" in that they must have a terminator. A NULL terminator in most cases, a '$' in the case of DOS, as in your code. Otherwise we all know what happens when you try to display a terminator-less string ...

Oh, sure, you can define a "string" internally in your code any way you like, but if you're going to use standard functions with it, Win32, Unix or DOS, it had better have a terminator!**
If you use standard functions, but that's isn't what defines a string. A string is just a sequence of usually printable characters with a few exceptions like cr, ln etc.. As the trick shows, you can define a string without a terminator and let use the function the terminator of the following string definition.

QuoteYour bringing up your "trick" (which is trivial and which anyone who ever wrote DOS assembly-language programs, as I did back in the day, was familiar with) doesn't change that. At some point in the string, there needs to be a terminator.
You still don't understand, that this is only for the string you pass over to a function that relies on the terminator. But the definition itself doesn't have that requirement, because you can append another string in memory that does have this terminator, thus your code will run fine.

NoCforMe

Quote from: bugthis on July 09, 2024, 09:40:25 AMBut the definition itself doesn't have that requirement, because you can append another string in memory that does have this terminator, thus your code will run fine.
But the fact remains that ultimately the string (whatever you pass to INT 21H/AH=9, f'rinstance) must have a terminator. How it (the terminator) gets there is irrelevant.
Assembly language programming should be fun. That's why I do it.

bugthis

Quote from: NoCforMe on July 09, 2024, 10:00:58 AM....(whatever you pass to INT 21H/AH=9, f'rinstance) must have a terminator.
Nobody here disputes that.

QuoteHow it (the terminator) gets there is irrelevant.
Exactly. And that's my point.


NoCforMe

Quote from: bugthis on July 09, 2024, 11:31:17 AM
QuoteHow it (the terminator) gets there is irrelevant.
Exactly. And that's my point.
OK. We can move on now.

You never answered: did you fix the problems with your code?
Assembly language programming should be fun. That's why I do it.

bugthis

Quote from: NoCforMe on July 09, 2024, 11:35:28 AM
Quote from: bugthis on July 09, 2024, 11:31:17 AM
QuoteHow it (the terminator) gets there is irrelevant.
Exactly. And that's my point.
OK. We can move on now.
I'm glad we got this settled.
QuoteYou never answered: did you fix the problems with your code?

Well, I now know the cause of the bug. And ultimately I just need to evaluate the parameters in a structured way. But I haven't gotten around to that today and I probably won't get around to it any time soon either, as I want to do a lot of other work first.

My program from yesterday was just a small test anyway, because my curiosity to read the VBE info block was too great. So it was just a quick and dirty mini test.