News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Option Literals:on "\n"

Started by aw27, September 03, 2017, 12:32:03 AM

Previous topic - Next topic

aw27

Why "\n" in a printf format string generates 0xD 0xD 0xA, i.e 2 carriages returns and 1 line feed?
You will be able to see it if you redirect the output to a text file.

habran

Can you give as a source where it happens, please?
Cod-Father

jj2007

#2
Here is one, and it definitely "happens", see attached executables and output:include \masm32\include\masm32rt.inc

.code
start:
  printf("Here\nis\none")
  exit

end start


Note the culprit is neither UAsm nor a notorious "third party include" - this works fine:
  print cfm$("Here\nis\nnone, hehe\n")

Note that invoke crt_setbuf, rv(GetStdHandle, STD_OUTPUT_HANDLE), 0 doesn't work, because C/C++ coders have their own ideas about stdout 8)

For the fans of hilarious and completely useless debates, here and here are threads that could make you feel good to be an assembler programmer :icon_mrgreen:

hutch--

 :biggrin:

> For the fans of hilarious and completely useless debates, here and here are threads that could make you feel good to be an assembler programmer

:P

aw27

Interestingly, neither MASM assembler nor UASM when assembling 32-bit translate "\n"


;include \masm32\include\masm32rt.inc

;ml -c -coff printcr.asm
;link /SUBSYSTEM:console printcr.obj

.386

.model flat, stdcall
option casemap :None

includelib \masm32\lib\msvcrt.lib
printf proto C :ptr, :vararg

.data
format0 db "Here\nis\none"

.code
start:
  invoke printf, offset format0
  ret

end start


Produces this output when redirected to a text file:
Here\nis\none

And in C:

int main()
{
    printf("Here\nis\none");
    return 0;
}

Produces this, which is what is expected, when redirected to a text file:
Here
is
one

It is true that the masm32rt.inc produces:
Here

is

one

but I was not saying that masm32rt.inc has no bugs.

And that UASM when assembling 64-bit like this:


option casemap :None
OPTION frame:auto
OPTION WIN64:2
option LITERALS:ON


includelib \masm32\lib64\kernel32.lib
ExitProcess proto :dword
includelib \masm32\lib64\msvcrt.lib
printf proto :ptr, :vararg

.code
start:
  invoke printf, "Here\nis\none"
  invoke ExitProcess,0

end start

Produces this, when redirected to a text file:
Here

is

one

What appears to happen is that C translates "\n" to 0xA in the format string, probably for compatibility with Linux, and inside the printf code it will add the carriage return.
UASM 64-bit translates "\n" to 0xD 0XA. Inside the code printf adds another carriage return and the result is what we see.

hutch--

Whats wrong with you guys, this is how a printf is handles in MASM32 thanks to a macro by Michael Webster.

Now come on, stop pulling our leg, write a MACRO that does it for you.  :P


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                     Build this console app with
                  "MAKEIT.BAT" on the PROJECT menu.
        ----------------------------------------------------- *

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    printf("How D awl\nThis is how its done in 32 bit MASM\nThis is because MASM is a MACRO assembler.\n");

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

aw27

Hi Hutch!

The macro produced by Michael Webster produces this when output is redirect to a file:

How D awl

This is how its done in 32 bit MASM

This is because MASM is a MACRO assembler.

If your text editor does not show that there are undesirable lines separating each line of text, you will be able to see that there are two consecutive carriage return before the line feed looking at the file with a hexeditor.  :t


Offset(d) 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15

00000000  48 6F 77 20 44 20 61 77 6C 0D 0D 0A 54 68 69 73  How D awl...This
00000016  20 69 73 20 68 6F 77 20 69 74 73 20 64 6F 6E 65   is how its done
00000032  20 69 6E 20 33 32 20 62 69 74 20 4D 41 53 4D 0D   in 32 bit MASM.
00000048  0D 0A 54 68 69 73 20 69 73 20 62 65 63 61 75 73  ..This is becaus
00000064  65 20 4D 41 53 4D 20 69 73 20 61 20 4D 41 43 52  e MASM is a MACR
00000080  4F 20 61 73 73 65 6D 62 6C 65 72 2E 0D 0D 0A     O assembler....




hutch--

Yes, you are right, I confess I have not had a look at that macro for a very long time.
This code,

main proc

    print cfm$("How D awl\nThis is how its done in 32 bit MASM\nThis is because MASM is a MACRO assembler.\n")

    ret

main endp


Produces when redirected,

How D awl
This is how its done in 32 bit MASM
This is because MASM is a MACRO assembler.
Press any key to continue ...


In hex,

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000  48 6F 77 20 44 20 61 77 6C 0D 0A 54 68 69 73 20  How D awl..This
00000010  69 73 20 68 6F 77 20 69 74 73 20 64 6F 6E 65 20  is how its done
00000020  69 6E 20 33 32 20 62 69 74 20 4D 41 53 4D 0D 0A  in 32 bit MASM..
00000030  54 68 69 73 20 69 73 20 62 65 63 61 75 73 65 20  This is because
00000040  4D 41 53 4D 20 69 73 20 61 20 4D 41 43 52 4F 20  MASM is a MACRO
00000050  61 73 73 65 6D 62 6C 65 72 2E 0D 0A 50 72 65 73  assembler...Pres
00000060  73 20 61 6E 79 20 6B 65 79 20 74 6F 20 63 6F 6E  s any key to con
00000070  74 69 6E 75 65 20 2E 2E 2E 0D 0A                 tinue .....

aw27

Yes, but the "print" macro does not call the MSVCRT function "printf".

What happens is that cfm$ is doing more than is asked for. "\n" is only a line feed escape sequence not a  carriage return+line feed escape sequence. There is an escape sequence to represent carriage return and it is "\r".
This makes it work with the macro "print" but not with the msvcrt function "printf".
Note that the msvcrt printf is smart enough to deal with format strings containing either "\n" or "\r\n" - it will never double the carriage return. What the msvcrt can't deal with is with a preprocessing of the format string replacing "\n" with 0xD + 0xA.
As a conclusion it appears that the problem is actually in the cmf$.
In my opinion, to avoid conflicts cmf$ should not do more than is asked for and just translate "\n" with 0xA. Who wants to use the macro "print" should write:
print cfm$("How D awl\r\nThis is how its done in 32 bit MASM\r\nThis is because MASM is a MACRO assembler.\r\n") and not print cfm$("How D awl\nThis is how its done in 32 bit MASM\nThis is because MASM is a MACRO assembler.\n")


jj2007

Quote from: aw27 on September 03, 2017, 01:56:42 PMprintf adds another carriage return

Yes indeed, that is part one of the problem: The CRT tries to "improve" the output by inserting a CR when it hits a LF, so CR LF becomes CR CR LF. An archaic "feature" from the early days of console printing, which unfortunately has been added to the C standard by the wisecracks of ISO. Solution: avoid the CRT.

There is a second problem with crt_printf which appears when you use it together with a standard print function (and it can be solved with the same solution :bgrin:):include \masm32\include\masm32rt.inc

.code
start:
  mov esi, chr$(10, "This", 10, "is", 10, "the", 10, "CRT", 10) ; foolproof?
  invoke crt_printf, esi
  push esi
  .While 1
lodsb
.Break .if !al
movzx eax, al
print str$(eax), " "
  .Endw
  pop esi
  invoke crt_printf, esi
  exit

end start


Output:This
is
the
CRT
10 84 104 105 115 10 105 115 10 116 104 101 10 67 82 84 10
This
is
the
CRT


Perfect, isn't it? Now open a DOS prompt, launch the attached exe, and you'll understand why Micros**t programmers nowadays produce garbled error messages from MASM.exe - they forgot to read the 1000-page C/C++ manual thoroughly :greensml:

aw27

Quote from: jj2007 on September 03, 2017, 05:19:49 PM
An archaic "feature" from the early days of console printing, which unfortunately has been added to the C standard by the wisecracks of ISO. Solution: avoid the CRT.

Unfortunately, I can not spend the whole day laughing.  :badgrin:

aw27

Another interesting fact about the  cfm$ macro is that it invented  "masm specific escapes" like \l for <, \r for >, \x for !, \a for ( and \b for ). The most amazing is not that its steals the "\r" (carriage return escape)  :dazzled:, the most amazing is that the escapes are absolutely unnecessary both for msvcrt prinft and for the GetStdHandle\WriteFile used by the print macro.  :icon_eek:

Vortex

No problem with Poasm :

.386
.model flat,stdcall
option casemap:none
option cstrings:on

printf      PROTO C :DWORD,:VARARG
ExitProcess PROTO :DWORD

includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\msvcrt.lib

.data

str1        db 'This\nis\na\ntest',0

.code

start:

    invoke  printf,ADDR str1

    invoke  ExitProcess,0

END start


CstringOption.exe

This
is
a
test

CstringOption.exe > Sample.txt

type Sample.txt

This
is
a
test


Disassembling the object module :
_data   SEGMENT DWORD PUBLIC 'DATA'

str1    label byte
        db 54H, 68H, 69H, 73H, 0AH, 69H, 73H, 0AH
        db 61H, 0AH, 74H, 65H, 73H, 74H, 00H

_data   ENDS



jj2007

Quote from: aw27 on September 03, 2017, 06:20:34 PMthe most amazing is that the escapes are absolutely unnecessary both for msvcrt prinft and for the GetStdHandle\WriteFile used by the print macro.  :icon_eek:

include \masm32\include\masm32rt.inc

.code
start:
  ; printf("Keep telling <nonsense>, José!") ; error A2045: missing angle bracket or brace in literal
  ; printf("Keep telling (nonsense\r, aw27!\n") ; error A2157: missing right parenthesis
  ; printf("Keep telling nonsense), aw27!\n") ; error A2046: missing single or double quotation mark in string
  printf("Keep telling \lnonsense\r, aw27!\n") ; ! missing
  printf("Keep telling \lnonsense\r, aw27\x\n") ; ! visible
  exit
end start


Output:Keep telling <nonsense>, aw27
Keep telling <nonsense>, aw27!

nidud

#14
deleted