[Info-vax] C limitations, was: Re: VMS process communication

Arne Vajhøj arne at vajhoej.dk
Sun Apr 16 13:33:05 EDT 2023


On 4/16/2023 1:26 PM, Arne Vajhøj wrote:
> On 4/12/2023 9:33 PM, Johnny Billquist wrote:
>> On 2023-04-12 16:44, Arne Vajhøj wrote:
>>> On 4/12/2023 10:41 AM, Arne Vajhøj wrote:
>>>> On 4/7/2023 4:58 PM, Johnny Billquist wrote:
>>>>> On 2023-04-03 14:31, bill wrote:
>>>>>> On 4/2/2023 8:50 PM, Johnny Billquist wrote:
>>>>>>> On 2023-03-29 19:51, bill wrote:
>>>>>>>> Weird?  What about under Primos where chars always have the high 
>>>>>>>> order
>>>>>>>> bit turned on?  It was called "mark memory parity" but it never 
>>>>>>>> made any
>>>>>>>> sense to me when I had to work with it.  :-)
>>>>>>>
>>>>>>> I think/suspect that this goes outside the scope of C...
>>>>>>
>>>>>> Of course it does.  But it affects C a lot more than other languages
>>>>>> if for no other reason than programming style.  How many Unix C 
>>>>>> programs
>>>>>> have you seen where parsing is done by looking at the value of a 
>>>>>> letter
>>>>>> as opposed to just comparing chars?  Even with Primix porting a Unix
>>>>>> program to a Pr1me was a serious task and often not even possible.
>>>>>
>>>>> I don't understand what you mean. Are you just talking about some 
>>>>> people assuming you have ASCII, and looking at the decimal values, 
>>>>> instead of the character representation. Basically writing 65 
>>>>> instead of 'A'?
>>>>> If so, that is certainly something I've seen in lots of languages, 
>>>>> and are in fact much more an issue in most other languages that 
>>>>> I've used, since they do not consider a thing like 'A' to be a 
>>>>> numeric value. C doing that really helps in this context.
>>>>>
>>>>> I'd say it's more common to see C code using the characters instead 
>>>>> of their numeric representation just because it is so easy to do in C.
>>>>
>>>> I believe there are basically two groups of languages:
>>>>
>>>> A) those where one can write both c=='A' and c==65
>>>> B) those where one can write c=='A' but c==65 gives a compile error 
>>>> and has to be written as ord(c)==65
>>>>
>>>> I find it more likely that group A will use 65 than group B.
>>>
>>> Examples of code:
>>
>> [...lots of code deleted...]
>>
>> The problem with this is that it is very artificial, and designed to 
>> prove your point.
> 
> Testing if a char is in the digit range is not an artificial problem.
> 
> Yes - the example was showing my point - it would have
> been pretty weird if I had produced an example that did
> not show my point.
> 
>> I can just as well give a counter example.
>>
>> Let's say you have a character that you know is a digit, and you want 
>> to convert it nicely to an integer.
>>
>> In C, you'd do that like this:
>>
>>     x = c - '0';
>>
>> In FORTRAN, BASIC, and god knows what else, you'd see:
>>
>>    x = ord(c) - 48;
>>
>> Now, I'd say I've seen plenty more of that than your type of example.
>> And I've *never* seen:
>>
>>    x = ord(c) - ord('0');
>>
>>
>> And yes, of course, you can also in C do:
>>
>>    x = c - 48;
>>
>> but I'd say that is less common, and a bad programmer will always 
>> manage to write bad code, no matter what language. That don't mean the 
>> language is bad. It is just more unclear, and in C there is no 
>> performance reason, or anything else giving any reason why you would 
>> write 48, when '0' is so much clearer what the intent is. And then it 
>> also works if you use another character set, as long as all the digits 
>> have consecutive code points.
> 
> I suspect that you are correct that x = c - '0' is more common
> than x = c - 48 in C and x = ord(c) - ord('0') is less common
> than x = ord(c) - 48 in more type safe languages.
> 
> But the construct should be very rare overall as most languages
> has easy to use and efficient builtin methods for that.
> 
> (and no it is not quite the same for checking if in digit range
> as doing conversion and check for error and regex are a bit
> heavy tools for the task).

And the usual code example to illustrate what I am talking
about.

$ type toint.c
#include <stdio.h>
#include <string.h>

int toint(const char *s)
{
     int res;
     sscanf(s, "%d", &res);
     return res;
}

int tointx(const char *s)
{
     int res, i;
     res = 0;
     for(i = 0; i < strlen(s); i++)
     {
         res = 10 * res + (s[i] - '0');
     }
     return res;
}

int tointxx(const char *s)
{
     int res, i;
     res = 0;
     for(i = 0; i < strlen(s); i++)
     {
         res = 10 * res + (s[i] - 48);
     }
     return res;
}

void test(const char *s)
{
     printf("\"%s\" : %d\n", s, toint(s));
     printf("\"%s\" : %d\n", s, tointx(s));
     printf("\"%s\" : %d\n", s, tointxx(s));
}

int main(int argc, char *argv[])
{
     test("1");
     test("12");
     test("123");
     return 0;
}
$ cc toint
$ link toint
$ run toint
"1" : 1
"1" : 1
"1" : 1
"12" : 12
"12" : 12
"12" : 12
"123" : 123
"123" : 123
"123" : 123
$ type toint.pas
program main(input,output);

type
    string = varying [255] of char;

function toint(s : string) : integer;

var
    res : integer;

begin
    readv(s, res);
    toint := res;
end;

function tointx(s : string) : integer;

var
    res, i : integer;

begin
    res := 0;
    for i := 1 to length(s) do begin
       res := 10 * res + (ord(s[i]) - ord('0'));
    end;
    tointx := res;
end;

function tointxx(s : string) : integer;

var
    res, i : integer;

begin
    res := 0;
    for i := 1 to length(s) do begin
       res := 10 * res + (ord(s[i]) - 48);
    end;
    tointxx := res;
end;

procedure test(s : string);

begin
    writeln('"', s, '" : ', toint(s):1);
    writeln('"', s, '" : ', tointx(s):1);
    writeln('"', s, '" : ', tointxx(s):1);
end;

begin
    test('1');
    test('12');
    test('123');
end.
$ pas toint
$ link toint
$ run toint
"1" : 1
"1" : 1
"1" : 1
"12" : 12
"12" : 12
"12" : 12
"123" : 123
"123" : 123
"123" : 123
$ type toint.for
       program main
       call test('1')
       call test('12')
       call test('123')
       end
c
       subroutine test(s)
       character*(*) s
       integer*4 toint, tointx, tointxx
       write(*,'(1x,a,3h : ,i3)') s, toint(s)
       write(*,'(1x,a,3h : ,i3)') s, tointx(s)
       write(*,'(1x,a,3h : ,i3)') s, tointxx(s)
       end
c
       integer*4 function toint(s)
       character*(*) s
       integer*4 res
       read(s,'(i)') res
       toint = res
       end
c
       integer*4 function tointx(s)
       character*(*) s
       integer*4 res, i
       res = 0
       do 100 i = 1, len(s)
         res = 10 * res + (ichar(s(i:i)) - ichar('0'))
100   continue
       tointx = res
       end
c
       integer*4 function tointxx(s)
       character*(*) s
       integer*4 res, i
       res = 0
       do 100 i = 1, len(s)
         res = 10 * res + (ichar(s(i:i)) - 48)
100   continue
       tointxx = res
       end
$ for toint
$ link toint
$ run toint
1 :   1
1 :   1
1 :   1
12 :  12
12 :  12
12 :  12
123 : 123
123 : 123
123 : 123
$ type toint.bas
program main

external sub test(string)

call test("1")
call test("12")
call test("123")

end program
!
sub test(string s)

external integer function toint(string)
external integer function tointx(string)
external integer function tointxx(string)

print using '"' + s + '" : ###', toint(s)
print using '"' + s + '" : ###', tointx(s)
print using '"' + s + '" : ###', tointxx(s)

end sub
!
function integer toint(string s)

declare integer res

res = integer(s)
toint = res

end function
!
function integer tointx(string s)

declare integer res, i

res = 0
for i = 1 to len(s)
     res = 10 * res + (asc(mid(s,i,1)) - asc("0"))
next i
tointx = res

end function
!
function integer tointxx(string s)

declare integer res

res = 0
for i = 1 to len(s)
     res = 10 * res + (asc(mid(s,i,1)) - 48)
next i
tointxx = res

end function
$ bas toint
$ link toint
$ run toint
"1" :   1
"1" :   1
"1" :   1
"12" :  12
"12" :  12
"12" :  12
"123" : 123
"123" : 123
"123" : 123
$ type ToInt.java
public class ToInt {
     public static int toInt(String s) {
         int res = Integer.parseInt(s);
         return res;
     }
     public static int toIntX(String s) {
         int res = 0;
         for(int i = 0; i < s.length(); i++) {
             res = 10 * res + (s.charAt(i) - '0');
         }
         return res;
     }
     public static int toIntXX(String s) {
         int res = 0;
         for(int i = 0; i < s.length(); i++) {
             res = 10 * res + (s.charAt(i) - '0');
         }
         return res;
     }
     public static void test(String s) {
         System.out.printf("\"%s\" : %d\n", s, toInt(s));
         System.out.printf("\"%s\" : %d\n", s, toIntX(s));
         System.out.printf("\"%s\" : %d\n", s, toIntXX(s));
     }
     public static void main(String[] args) throws Exception {
         test("1");
         test("12");
         test("123");
     }
}
$ javac ToInt.java
$ java "ToInt"
"1" : 1
"1" : 1
"1" : 1
"12" : 12
"12" : 12
"12" : 12
"123" : 123
"123" : 123
"123" : 123
$ type toint.py
def toint(s):
     res = int(s)
     return res

def tointx(s):
     res = 0
     for c in s:
         res = 10 * res + (ord(c) - ord('0'))
     return res

def tointxx(s):
     res = 0
     for c in s:
         res = 10 * res + (ord(c) - 48)
     return res

def test(s):
     print('"%s" : %d' % (s, toint(s)))
     print('"%s" : %d' % (s, tointx(s)))
     print('"%s" : %d' % (s, tointxx(s)))

test('1')
test('12')
test('123')
$ python toint.py
"1" : 1
"1" : 1
"1" : 1
"12" : 12
"12" : 12
"12" : 12
"123" : 123
"123" : 123
"123" : 123

Arne

PS: For the C code I guess that atoi or strtol would actually
     be a lot more efficient than sscanf, but there are certainly
     functions available.






More information about the Info-vax mailing list