DFS <nospam@dfs.com> writes:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
My code works fine locally (prints the correct solution to the
console), but when I submit the .c file the auto-tester flags it with
'runtime error' and says the output is empty.
------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// n = 3: output is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int len = 0;
char result[10000] = "";
sprintf(result, "%d ", n);
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if(n != 1)
{
len = strlen(result);
sprintf(result + len, "%d ", n);
}
else
break;
}
len = strlen(result);
sprintf(result + len, "1 ");
printf("%s\n",result);
return 0;
}
------------------------------------------------------------
I don't see any problem with the code, and neither does gcc on
my system.
But the code you posted contains a number of NO-BREAK
SPACE characters (0xa0). "clang -Wno-unicode-whitespace" accepts
those characters without complaint, and gives non-fatal warnings
without that option. gcc treats them as a fatal error.
A minor point: You print a trailing space. I don't know whether
the auto-tester will accept that.
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
My code works fine locally (prints the correct solution to the
console), but when I submit the .c file the auto-tester flags it with
runtime error' and says the output is empty.
------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// n = 3: output is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int len = 0;
char result[10000] = "";
sprintf(result, "%d ", n);
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if(n != 1)
{
len = strlen(result);
sprintf(result + len, "%d ", n);
}
else
break;
}
len = strlen(result);
sprintf(result + len, "1 ");
printf("%s\n",result);
return 0;
}
------------------------------------------------------------
Any ideas?
But my main concern right now is getting my submission to work
with their auto-tester. All it says is 'runtime error' and
'empty output'.
Any ideas what I might be doing wrong?
DFS <nospam@dfs.com> writes:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
My code works fine locally (prints the correct solution to the
console), but when I submit the .c file the auto-tester flags it with
runtime error' and says the output is empty.
------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// n = 3: output is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int len = 0;
char result[10000] = "";
sprintf(result, "%d ", n);
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if(n != 1)
{
len = strlen(result);
sprintf(result + len, "%d ", n);
}
else
break;
}
len = strlen(result);
sprintf(result + len, "1 ");
printf("%s\n",result);
return 0;
}
------------------------------------------------------------
Any ideas?
Have you thought about how large the value of 'n' can
become inside the while() loop?
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and write
output to standard output."
The autotester expects your program to read arguments from stdin, not
from command line arguments.
It probably passes no arguments to your program, so argv[1] is a null pointer. It's likely your program compiles (assuming the NBSP
characters were added during posting) and crashes at runtime, producing
no output.
Pretty easy fixes:
1 use scanf()
2 update int to long
3 handle special case of n = 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
On 19/03/2025 04:42, DFS wrote:
Pretty easy fixes:
1 use scanf()
2 update int to long
3 handle special case of n = 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
You've also fixed another glitch which may or may not have been
significant:
$ file post2.txt
post2.txt: news, ASCII text
So wherever that UTF-8 came from, it's gone now.
Have you thought about how large the value of 'n' can
become inside the while() loop?
On 3/19/2025 12:51 AM, Richard Heathfield wrote:
On 19/03/2025 04:42, DFS wrote:
Pretty easy fixes:
1 use scanf()
2 update int to long
3 handle special case of n = 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
You've also fixed another glitch which may or may not have been
significant:
$ file post2.txt
post2.txt: news, ASCII text
So wherever that UTF-8 came from, it's gone now.
Cool. Thanks for looking at it.
Hey, how are your C book (from 2000) sales? Thought about a new
edition?
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. [...]
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
My code works fine locally (prints the correct solution to the console),
but when I submit the .c file the auto-tester flags it with 'runtime
error' and says the output is empty.
------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// n = 3: output is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int len = 0;
char result[10000] = "";
sprintf(result, "%d ", n);
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if(n != 1)
{
len = strlen(result);
sprintf(result + len, "%d ", n);
}
else
break;
}
len = strlen(result);
sprintf(result + len, "1 ");
printf("%s\n",result);
return 0;
}
------------------------------------------------------------
Any ideas?
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
len = strlen(result);
sprintf(result + len, "%d ", n);
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
len = strlen(result);
sprintf(result + len, "%d ", n);
And what's odd here is collating the results in a string (especially
when the possible number of steps is unknown). Why not just print it straight to the console?
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
len = strlen(result);
sprintf(result + len, "%d ", n);
And what's odd here is collating the results in a string (especially
when the possible number of steps is unknown). Why not just print it
straight to the console?
On Tue, 18 Mar 2025 21:38:55 -0400
DFS <nospam@dfs.com> wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
It is not an interesting programming exercise.
But it looks to me as a
challenging math exercise. I mean, how could we give a not too
pessimistic estimate for upper bound of length of the sequence that
starts at given n without running a full sequence? Or estimate for
maximal value in the sequence?
So far, I found no answers.
On 3/19/2025 6:15 AM, bart wrote:
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
I wouldn't have known it was a famous math conjecture, but no doubt the >author of the problem did.
Reading wikipedia it looks like one of those dull problems
mathematicians think up when they've got too much free time on their
hands.
On Wed, 19 Mar 2025 14:40:38 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
Reading wikipedia it looks like one of those dull problems
mathematicians think up when they've got too much free time on their
hands.
Yeah, one of those dull problems that most of the times remain obscure,
but occasionally end up providing the rest of world with things like >public-key cryptography.
On 2025-03-19, DFS <nospam@dfs.com> wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
What happens if the input is a negative number?
On Wed, 19 Mar 2025 10:15:58 +0000
bart <bc@freeuk.com> wrote:
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
Thank you. Wikipedia article about Collatz Conjecture is a good reading.
On 3/19/2025 5:55 AM, Michael S wrote:
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I
needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment
(supposedly, x86-64 Linux) used both by yourself and by the
server that
tests results.
In more general case, 'long' is not guaranteed to handle
numbers in
range up to 18,997,161,173 that can happen in this test.
How did you determine that?
int64_t n = 0, max = 0, thismax = 0;...
printf("\nmax n = %lld reached at input = %d\n", max, input);...
You'll get compilation warnings about the printf specifier used with
int64_t.
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment (supposedly, x86-64 Linux) used both by yourself and by the server that
tests results.
In more general case, 'long' is not guaranteed to handle numbers in
range up to 18,997,161,173 that can happen in this test.
Something like int64_t would be safer.
DFS <nospam@dfs.com> writes:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. [...]
Yes, I knew that already. Did you think I asked the question
without having first investigated the problem?
On 19/03/2025 17:23, DFS wrote:
On 3/19/2025 5:55 AM, Michael S wrote:
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I
needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment
(supposedly, x86-64 Linux) used both by yourself and by the
server that
tests results.
In more general case, 'long' is not guaranteed to handle
numbers in
range up to 18,997,161,173 that can happen in this test.
How did you determine that?
By the language definition.
++++++++++++++++++++++++++++++++++++++++++++++
5.2.4.2.1 Sizes of integer types <limits.h>
[...]
— minimum value for an object of type long int
LONG_MIN
-2147483647 // −(231 − 1)
— maximum value for an object of type long int
LONG_MAX
+2147483647 // 231 − 1
++++++++++++++++++++++++++++++++++++++++++++++
That is, the long int type is required to have a sign bit and at
least 31 value bits, giving a guaranteed minimum range of
-2147483647 to 2147483647. That's 2 thou mill.
You can squeeze another bit out of it by going unsigned: 0 to
4294967295. That's 4 thou mill.
From C99 onwards you can use long long int to give you 63 (or 64
for unsigned) value bits - printf with %lld or %llu. Roughly 9
mill mill mill and 18 mill mill mill respectively.
More interesting question is "How do*you* know about this newfangled gibberish?" :-)
On 3/19/25 13:23, DFS wrote:
...
int64_t n = 0, max = 0, thismax = 0;...
printf("\nmax n = %lld reached at input = %d\n", max, input);...
You'll get compilation warnings about the printf specifier used with
int64_t.
Not if you use the correct specifier:
#include <inttypes.h>
printf("\nmax n = %" PRId64 " reached at input = %d\n", max, input);
On 3/19/2025 1:27 AM, Tim Rentsch wrote:
DFS <nospam@dfs.com> writes:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. [...]
Yes, I knew that already. Did you think I asked the question
without having first investigated the problem?
I wouldn't presume.
Did you investigate first?
I just now did:
gcc on Kali Linux (in Windows WSL)
run it: $ ./weird start stop
$time ./weird 1 1000000
<1000000 lines will be output>
max n = 56991483520 reached at input = 704511
real 0m5.792s
code
-----------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// example: the sequence for n=3 is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int steps, input;
int startN = atoi(argv[1]);
int stopN = atoi(argv[2]);
int64_t n = 0, max = 0, thismax = 0;
for (int i = startN; i <= stopN; i++) {
n = i;
steps = 1;
thismax = n;
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if (n > max) {max = n; input = i;}
if (n > thismax) {thismax = n;}
steps++;
if (i == 1) {
printf("input 1, max n = 1, steps = 1\n");
break;
}
if(n == 1) {
printf("input %d, max n = %6lld, steps = %4d\n",
i, thismax, steps);
break;
}
}
}
printf("\nmax n = %lld reached at input = %d\n", max, input);
return 0;
}
-----------------------------------------------------------------
You'll get compilation warnings about the printf specifier used with
int64_t.
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment (supposedly, x86-64 Linux) used both by yourself and by the server that
tests results.
In more general case, 'long' is not guaranteed to handle numbers in
range up to 18,997,161,173 that can happen in this test.
Something like int64_t would be safer.
Michael S <already5chosen@yahoo.com> writes:
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment (supposedly, x86-64 Linux) used both by yourself and by the server
that tests results.
In more general case, 'long' is not guaranteed to handle numbers in
range up to 18,997,161,173 that can happen in this test.
The number 18997161173 is odd. The largest value reached is three
times that, plus 1, which is 56991483520.
Something like int64_t would be safer.
Using unsigned long long is safer still, and easier, because there
is no need for hoop-jumping to print them out with printx.
On Wed, 19 Mar 2025 09:03:33 -0400
DFS <nospam@dfs.com> wibbled:
On 3/19/2025 6:15 AM, bart wrote:
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
I wouldn't have known it was a famous math conjecture, but no
doubt the author of the problem did.
Reading wikipedia it looks like one of those dull problems
mathematicians think up when they've got too much free time on
their hands.
Ike Naar <ike@sdf.org> writes:
On 2025-03-19, DFS <nospam@dfs.com> wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
I've been playing with some of these myself.
I'm actually using
scanf() for integer input, something I wouldn't do in normal code
(because the behavior is undefined if the scanned value is out
of range). This is a rare case where it's safe to assume that
stdin has nothing harmful.
On 3/19/2025 4:53 AM, Keith Thompson wrote:
I'm actually using
scanf() for integer input, something I wouldn't do in normal code
(because the behavior is undefined if the scanned value is out
of range). This is a rare case where it's safe to assume that
stdin has nothing harmful.
My very 1st submission for 'Missing Number' was accepted, but
each use of scanf() generated a warning:
//identify the missing number in a set of consecutive integers
On 19/03/2025 20:45, DFS wrote:
On 3/19/2025 4:53 AM, Keith Thompson wrote:
<snip>
I'm actually using
scanf() for integer input, something I wouldn't do in normal code
(because the behavior is undefined if the scanned value is out
of range). This is a rare case where it's safe to assume that
stdin has nothing harmful.
My very 1st submission for 'Missing Number' was accepted, but
each use of scanf() generated a warning:
Like Keith, I don't usually use scanf.
My preference is to read the number into a text buffer using
fgets, and then convert it using strtoul if I can, or strtol if I
have to allow for negatives.
//identify the missing number in a set of consecutive integers
Not sure why you're sorting and malloc-ing.
Loop through the input, adding as you go.
Let the first number be x.
Let the last number be y.
Let the total of all numbers be t.
Let m = ((y*(y+1))-(x*(x+1)))/2 - t;
"The missing number is: %lld\n", m
DFS <nospam@dfs.com> writes:
On 3/19/2025 4:53 AM, Keith Thompson wrote:
I used a different approach. I'll encode the description of the
solution using rot13.
The program is given an integer n and a list of n-1 integers, not
necessarily ordered.
The task is to determine which number is missing from the list.
Gurer'f n jryy xabja sbezhyn sbe gur fhz bs nyy a ahzoref sebz bar
gb a. Pbzchgr gur rkcrpgrq fhz, gura fhogenpg gur fhz bs gur ahzoref
tvira ba gur frpbaq vachg yvar. Gur qvssrerapr vf gur zvffvat ahzore.
Muttley@DastardlyHQ.org writes:
On Wed, 19 Mar 2025 09:03:33 -0400
DFS <nospam@dfs.com> wibbled:
On 3/19/2025 6:15 AM, bart wrote:
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
I wouldn't have known it was a famous math conjecture, but no
doubt the author of the problem did.
Reading wikipedia it looks like one of those dull problems
mathematicians think up when they've got too much free time on
their hands.
The 3n+1 problem, as it is sometimes called, is interesting
because it is easy to state and easy to understand, even without
any mathematical training beyond grade school, and yet has
resisted the efforts of many of the best mathematicians in the
world to try to prove it. It seems like it should be easy, but
it is in fact incredibly difficult, based on almost 100 years of
experience.
On Wed, 19 Mar 2025 17:38:12 +0000
Richard Heathfield <rjh@cpax.org.uk> wrote:
On 19/03/2025 17:23, DFS wrote:
On 3/19/2025 5:55 AM, Michael S wrote:
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I
needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment
(supposedly, x86-64 Linux) used both by yourself and by the
server that
tests results.
In more general case, 'long' is not guaranteed to handle
numbers in
range up to 18,997,161,173 that can happen in this test.
How did you determine that?
By the language definition.
Well, not exactly.
I never read C Standard docs except the very first one that I read
more that I read more than 33 years ago, so not very likely to
remember it literally.
Let's say that I know this particular bit of trivia from 1st hand
experience and from reading few ABI definitions.
++++++++++++++++++++++++++++++++++++++++++++++
5.2.4.2.1 Sizes of integer types <limits.h>
[...]
? minimum value for an object of type long int
LONG_MIN
-2147483647 // ?(231 ? 1)
? maximum value for an object of type long int
LONG_MAX
+2147483647 // 231 ? 1
++++++++++++++++++++++++++++++++++++++++++++++
That is, the long int type is required to have a sign bit and at
least 31 value bits, giving a guaranteed minimum range of
-2147483647 to 2147483647. That's 2 thou mill.
You can squeeze another bit out of it by going unsigned: 0 to
4294967295. That's 4 thou mill.
From C99 onwards you can use long long int to give you 63 (or 64
for unsigned) value bits - printf with %lld or %llu. Roughly 9
mill mill mill and 18 mill mill mill respectively.
I suspected that, but was not sure, so suggested to DFS a type that I am
sure about.
On Wed, 19 Mar 2025 13:13:45 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wibbled:
Muttley@DastardlyHQ.org writes:
On Wed, 19 Mar 2025 09:03:33 -0400
DFS <nospam@dfs.com> wibbled:
On 3/19/2025 6:15 AM, bart wrote:
On 19/03/2025 01:38, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
This is related to the Collatz Conjecture. What's weird is not
mentioning it.
I wouldn't have known it was a famous math conjecture, but no
doubt the author of the problem did.
Reading wikipedia it looks like one of those dull problems
mathematicians think up when they've got too much free time on
their hands.
The 3n+1 problem, as it is sometimes called, is interesting
because it is easy to state and easy to understand, even without
any mathematical training beyond grade school, and yet has
resisted the efforts of many of the best mathematicians in the
world to try to prove it. It seems like it should be easy, but
it is in fact incredibly difficult, based on almost 100 years of
experience.
I guess some maths problems can't be proven directly, they have to
be - for want of a better word - run. A bit like the halting
problem in CS.
On 19/03/2025 05:02, DFS wrote:
On 3/19/2025 12:51 AM, Richard Heathfield wrote:
On 19/03/2025 04:42, DFS wrote:
Pretty easy fixes:
1 use scanf()
2 update int to long
3 handle special case of n = 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
You've also fixed another glitch which may or may not have been
significant:
$ file post2.txt
post2.txt: news, ASCII text
So wherever that UTF-8 came from, it's gone now.
Cool. Thanks for looking at it.
Hey, how are your C book (from 2000) sales? Thought about a new
edition?
I'm not sure a new edition is necessary, but if it is to be
written it would be better served by someone like Keith or Tim,
both of whom have (as I have not) kept up with the million-and-one
changes that appear to have assailed the simple language I once
enjoyed.
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am
sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
On Wed, 19 Mar 2025 12:59:13 -0700
Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
Michael S <already5chosen@yahoo.com> writes:
On Wed, 19 Mar 2025 00:38:44 -0400
DFS <nospam@dfs.com> wrote:
On 3/18/2025 11:07 PM, Tim Rentsch wrote:
Have you thought about how large the value of 'n' can
become inside the while() loop?
I was too smug in my first reply. After Keith pointed out I needed
to read from stdin, I submitted the code again and it passed some
tests but failed with 'OUTPUT LIMIT EXCEEDED' when n = 159487.
Updating int to long worked, and now I'm bona fide!
So thanks.
What you did happens to be sufficient for a particular environment
(supposedly, x86-64 Linux) used both by yourself and by the server
that tests results.
In more general case, 'long' is not guaranteed to handle numbers in
range up to 18,997,161,173 that can happen in this test.
The number 18997161173 is odd. The largest value reached is three
times that, plus 1, which is 56991483520.
Yes, my mistake.
I only looked for maximal odd number in the sequence. Forgot about
even numbers.
Something like int64_t would be safer.
Using unsigned long long is safer still, and easier, because there
is no need for hoop-jumping to print them out with printx.
I explained the reason in the reply to Richard Heathfield.
On Tue, 18 Mar 2025 21:38:55 -0400
DFS <nospam@dfs.com> wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
It is not an interesting programming exercise. But it looks to me as a challenging math exercise. I mean, how could we give a not too
pessimistic estimate for upper bound of length of the sequence that
starts at given n without running a full sequence? Or estimate for
maximal value in the sequence?
So far, I found no answers.
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why
not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
So long can't be used in programs intended to be portable to
other operating systems.
type in both Windows and Linux.
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular implementation. No useful implementation would fail to define
uint64_t in these modern times.
Richard Heathfield <rjh@cpax.org.uk> writes:
I'm not sure a new edition is necessary, but if it is to be
written it would be better served by someone like Keith or Tim,
both of whom have (as I have not) kept up with the million-and-one
changes that appear to have assailed the simple language I once
enjoyed.
The C99 standard has a list of 54 what it calls "major changes",
although IMO many or most of those are fairly minor. There are also
other differences relative to C90, but most of them are simply
clarifications or slight changes in wording.
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why
not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type
that I am sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then
why not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
So long can't be used in programs intended to be portable to
other operating systems. 'long long' is defined as a 64-bit
type in both Windows and Linux.
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular implementation. No useful implementation would fail to define
uint64_t in these modern times.
On 20/03/2025 13:36, Scott Lurndal wrote:then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
Unix and Linux define it as 32 bits on 32-bit architectures and 64 bits
on 64-bit ones.
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why
not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
I see now from casual research that C17 was predominantly a bug
fix, but that C11 and C23 were somewhat busier.
On 20/03/2025 13:36, Scott Lurndal wrote:
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular
implementation. No useful implementation would fail to define
uint64_t in these modern times.
The point was made earlier on that int64_t types are awkward to work
with; they need that stdint.h header to even exist, and they need those
ugly macros in inttypes.h to print out their values.
This is why it popular to just do:
typedef long long int i64;
stdint.h et al are just ungainly bolt-ons, not fully supported by the >language.
So somebody eschewing those ugly macros and using "%ld" to print an
What makes you think they're macros?
bart <bc@freeuk.com> writes:
On 20/03/2025 13:36, Scott Lurndal wrote:then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
Unix and Linux define it as 32 bits on 32-bit architectures and 64 bits
on 64-bit ones.
That's what I said. Thanks for the confirmation. It doesn't change
the fact that Microsoft didn't define long as 64-bit on 64-bit architectures, creating incompatibilities that didn't exist in the 32-bit world
between the two dominant operating systems.
Remainder of bart's typical windows-centric complaints elided.
On Thu, 20 Mar 2025 14:50:25 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
What makes you think they're macros?
PRIu64 and PRId64 are macros. They are ugly.
On Thu, 20 Mar 2025 16:59:14 +0200
Michael S <already5chosen@yahoo.com> wibbled:
On Thu, 20 Mar 2025 14:50:25 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
What makes you think they're macros?
PRIu64 and PRId64 are macros. They are ugly.
Never even heard of them. Looking them up I can't see much use for
them frankly except if you're starting out on an unknown system and
can't find out the info any other way which would be ... odd.
On Thu, 20 Mar 2025 14:00:29 +0000
bart <bc@freeuk.com> wibbled:
On 20/03/2025 13:36, Scott Lurndal wrote:
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular
implementation. No useful implementation would fail to define
uint64_t in these modern times.
The point was made earlier on that int64_t types are awkward to work
with; they need that stdint.h header to even exist, and they need those
ugly macros in inttypes.h to print out their values.
I've never found them awkward to work with and every *nix I've ever developed on had stdint.h. If Windows doesn't thats Window's problem.
This is why it popular to just do:
typedef long long int i64;
Popular maybe in WindowsWorld. Why as a unix dev would I do that when standard typedefs already exist for this exact purpose?
stdint.h et al are just ungainly bolt-ons, not fully supported by the
language
Whats that supposed to mean? The core language itself supports very little. Do you not use libraries at all?
So somebody eschewing those ugly macros and using "%ld" to print an
What makes you think they're macros?
MacOS:
stdint.h
_types/_uint64_t.h
typedef unsigned long long uint64_t;
On Thu, 20 Mar 2025 15:16:05 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
On Thu, 20 Mar 2025 16:59:14 +0200
Michael S <already5chosen@yahoo.com> wibbled:
On Thu, 20 Mar 2025 14:50:25 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
What makes you think they're macros?
PRIu64 and PRId64 are macros. They are ugly.
Never even heard of them. Looking them up I can't see much use for
them frankly except if you're starting out on an unknown system and
can't find out the info any other way which would be ... odd.
Then how exactly do you printf value of type int64_t in a code that
expected to pass [gcc] compilation with no warnings on two platforms,
one of which is 64-bit Unix/Linux and another is just about anything
else?
On 20/03/2025 14:50, Muttley@DastardlyHQ.org wrote:
On Thu, 20 Mar 2025 14:00:29 +0000
bart <bc@freeuk.com> wibbled:
On 20/03/2025 13:36, Scott Lurndal wrote:
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular
implementation. No useful implementation would fail to define
uint64_t in these modern times.
The point was made earlier on that int64_t types are awkward to work
with; they need that stdint.h header to even exist, and they need those
ugly macros in inttypes.h to print out their values.
I've never found them awkward to work with and every *nix I've ever developed
on had stdint.h. If Windows doesn't thats Window's problem.
stdint.h is part of a C compiler; it's nothing to do with Windows. My
remark was about having to write '#include <stdio.h>' on each one of the
100 modules of your project if you want tto use basic language data types.
I guess some maths problems can't be proven directly, they have to be - for want of a better word - run. A bit like the halting problem in CS.
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
I guess some maths problems can't be proven directly, they have to be - for >> want of a better word - run. A bit like the halting problem in CS.
The halting problem is a perfect example of a problem which *cannot* be >proven by running anything.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
On Thu, 20 Mar 2025 16:14:54 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
I guess some maths problems can't be proven directly, they have to be - for >>> want of a better word - run. A bit like the halting problem in CS.
The halting problem is a perfect example of a problem which *cannot* be >>proven by running anything.
So if you run the program and it halts that doesn't prove that it will halt? Umm, ok.
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect.
If 'int' doesn't need to store values beyond 16 bits, then
why not use 'short'?
On 20/03/2025 13:06, Tim Rentsch wrote:
Richard Heathfield <rjh@cpax.org.uk> writes:
<snip>
I'm not sure a new edition is necessary, but if it is to be
written it would be better served by someone like Keith or Tim,
both of whom have (as I have not) kept up with the million-and-one
changes that appear to have assailed the simple language I once
enjoyed.
The C99 standard has a list of 54 what it calls "major changes",
although IMO many or most of those are fairly minor. There are also
other differences relative to C90, but most of them are simply
clarifications or slight changes in wording.
Those I largely recall from discussions at the time, but I dare to
conclude that your lack of a reference to C11, C17, and C23 means that
they had a lesser effect on the language than I'd feared.
I see now from casual research that C17 was predominantly a bug fix,
but that C11 and C23 were somewhat busier.
Pretty much every other open source project I look likes to define
their own types!
So I have to ask, why do think they do that?
My understanding of what was done in the C17 standard agrees with
your casual research, except I might have said "almost entirely"
rather than "predominantly".
I have not spent nearly as much time looking at the C23, especially
in comparison with C99 or C11. Based on what little I do know about
C23, I consider that version of C to be one best avoided, for at
least a decade and perhaps more. I may have more to say about that
at some point in the future but do not have anything right now.
On Thu, 20 Mar 2025 15:16:05 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
On Thu, 20 Mar 2025 16:59:14 +0200
Michael S <already5chosen@yahoo.com> wibbled:
On Thu, 20 Mar 2025 14:50:25 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
What makes you think they're macros?
PRIu64 and PRId64 are macros. They are ugly.
Never even heard of them. Looking them up I can't see much use for
them frankly except if you're starting out on an unknown system and
can't find out the info any other way which would be ... odd.
Then how exactly do you printf value of type int64_t in a code that
expected to pass [gcc] compilation with no warnings on two platforms,
one of which is 64-bit Unix/Linux and another is just about anything
else?
On Thu, 20 Mar 2025 15:40:20 +0000
bart <bc@freeuk.com> wrote:
Pretty much every other open source project I look likes to define
their own types!
So I have to ask, why do think they do that?
Most likely mindless parroting of 40 y.o. examples.
On 20/03/2025 18:46, Michael S wrote:
On Thu, 20 Mar 2025 15:40:20 +0000
bart <bc@freeuk.com> wrote:
Pretty much every other open source project I look likes to define
their own types!
So I have to ask, why do think they do that?
Most likely mindless parroting of 40 y.o. examples.
I don't think so. Where such sets of types exist, they tend to be
defined on top of long long too, or even on top of stdint.h types.
Look at this one for example:
typedef uint8_t byte; // from arduino.h
I can only one of reason this exists, which is that 'byte' is a far
nicer denotation.
You might also consider why such examples existed even 40 years ago.
It's an embarrassing blemish on Rust that they made their principal
integer types like this; it makes all Rust code look idiotically
hardware dependent. You can't code an abstract algorithm out of
Sedgewick, Knuth or Cormen in Rust without peppering the code with distracting 32's and 64's.
bart <bc@freeuk.com> writes:
[...]
This is why it popular to just do:
typedef long long int i64;
and to use %lld to print, and -LL on literals to force a 64-bit type.
Is it? I don't recall seeing anyone other than you do that.
stdint.h et al are just ungainly bolt-ons, not fully supported by the
language.
No, they're fully supported by the language. They've been in the ISO standard since 1999.
The problem with 'long' manifests itself there too, since on Linux,
'int64_t' appears to be commonly defined on top of 'long' for 32-bit
systems, and 'long long' for 64-bit ones.
If you're writing code for which that's a problem, you probably need to
fix your code.
So somebody eschewing those ugly macros and using "%ld" to print an
'int64_t' type, will find it doesn't work when run on a 64-bit system,
where "%lld" is needed. Same problem with using '1L' to define an
int64_t literal.
Somebody writing blatantly non-portable code will run into problems when
they try to port it.
I understand that you dislike <stdint.h>. That's both perfectly
acceptable and not very interesting.
On Thu, 20 Mar 2025 19:58:37 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wrote:
It's an embarrassing blemish on Rust that they made their principal
integer types like this; it makes all Rust code look idiotically
hardware dependent. You can't code an abstract algorithm out of
Sedgewick, Knuth or Cormen in Rust without peppering the code with
distracting 32's and 64's.
If size suffixes make you nervous, Rust has equivalents of size_t and ptrdiff_t. Named, respectively, usize and isize.
But you probably know it.
bart <bc@freeuk.com> writes:
On 20/03/2025 19:10, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
stdint.h et al are just ungainly bolt-ons, not fully supported by theNo, they're fully supported by the language. They've been in the ISO
language.
standard since 1999.
I don't think so. They are add-ons that could have been created in
user-code even prior to C99 (user-defined typedefs for 64 bits would
'need long long').
Sure, they could; see Doug Gwyn's q8, for example.
All that's happened is that 'stdint.h' has been blessed.
I.e., it was made part of the language, specifically the standard
library that's part of the language standard. Which is what I said,
but for some reason you disagreed.
Yes, the format specifiers are a bit awkward. Boo hoo.
On 20/03/2025 18:24, Tim Rentsch wrote:
<snip>
My understanding of what was done in the C17 standard agrees with
your casual research, except I might have said "almost entirely"
rather than "predominantly".
I have not spent nearly as much time looking at the C23, especially
in comparison with C99 or C11. Based on what little I do know about
C23, I consider that version of C to be one best avoided, for at
least a decade and perhaps more. I may have more to say about that
at some point in the future but do not have anything right now.
Thank you for your reply, which as ever was cogent and highly
informative.
On 20/03/2025 23:18, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 20/03/2025 19:10, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
stdint.h et al are just ungainly bolt-ons, not fully supported by the >>>>> language.No, they're fully supported by the language. They've been in the ISO
standard since 1999.
I don't think so. They are add-ons that could have been created in
user-code even prior to C99 (user-defined typedefs for 64 bits would
'need long long').
Sure, they could; see Doug Gwyn's q8, for example.
Isn't that what I said? However I've just looked at this 700-line header:
https://www.lysator.liu.se/c/q8/stdint.h
Sorry, but there's something wrong if you have to write all that to get
a handful of fixed-width types.
(And if this is for a multitude of
targets, then there should be a dedicated header per target).
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part
of the core language, it would be zero lines.
On 2025-03-20, bart <bc@freeuk.com> wrote:
On 20/03/2025 23:18, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 20/03/2025 19:10, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
stdint.h et al are just ungainly bolt-ons, not fully supported by the >>>>>> language.No, they're fully supported by the language. They've been in the ISO >>>>> standard since 1999.
I don't think so. They are add-ons that could have been created in
user-code even prior to C99 (user-defined typedefs for 64 bits would
'need long long').
Sure, they could; see Doug Gwyn's q8, for example.
Isn't that what I said? However I've just looked at this 700-line header:
https://www.lysator.liu.se/c/q8/stdint.h
Sorry, but there's something wrong if you have to write all that to get
a handful of fixed-width types.
That's not all that is needed; the material in Q8defs.h is required
to make the material in the above file work.
It's not just the types, but all the standard-required identifiers.
I feel that this Q8 could probably have been organized a little
differently to make it more compact.
The Q8defs.h header already has conditionals for platforms.
Then Q8's inttypes.h still has to switch on some more abstract
conditions in the preprocessor to select the types.
This two layer business could just be one, more or less.
Q8defs.h could just define, for instance, q8_uintptr_t,
for each platform, and then inttypes just has to expose it under the
standard name:
typedef q8_uintptr_t uintptr_t;
(And if this is for a multitude of
targets, then there should be a dedicated header per target).
What? That would pretty much defeat the whole point of this Q8 library.
What would would select which file to use where?
You drop those files into your C90, and then you have a facsimile
of C99 compatibility, on all the platforms supported by Q8.
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part
Q8 tries to add the C99 stuff for something like 7 implementations
or implementation familes. GCC is one implementation, but with
many targets.
of the core language, it would be zero lines.
This kind of argumentation is really not of good quality.
A feature requires lines of code. If those lines are not in some
satellite file like a C header, then they are elsewhere, like in the
compiler source code.
It's not "zero lines" because you hid it in the compiler.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
Michael S <already5chosen@yahoo.com> writes:
On Tue, 18 Mar 2025 21:38:55 -0400
DFS <nospam@dfs.com> wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
It is not an interesting programming exercise. But it looks to me
as a challenging math exercise. I mean, how could we give a not
too pessimistic estimate for upper bound of length of the sequence
that starts at given n without running a full sequence? Or
estimate for maximal value in the sequence? So far, I found no
answers.
You may console yourself with the knowledge that no one else
has either, even some of the most brilliant mathematicians
of the last hundred years. In fact it isn't even known that
all starting points eventually terminate; as far as what has
been proven goes, some starting points might just keep going
up forever.
I think someone has mentioned that this is called the Collatz
Conjecture. According to Wikipedia, it's been shown to hold for
all positive integers up to 2.95e20 (which is just under 2**68).
I would be astonished if anyone disproved it.
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
On Thu, 20 Mar 2025 16:14:54 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
I guess some maths problems can't be proven directly, they have to be - >for
want of a better word - run. A bit like the halting problem in CS.
The halting problem is a perfect example of a problem which *cannot* be >>>proven by running anything.
So if you run the program and it halts that doesn't prove that it will halt? >> Umm, ok.
If you run a program and it has NOT halted so far, you don't know
whether or not it halts. If it doesn't halt, you will wait forever. To
bart <bc@freeuk.com> writes:
You're complaining about how much work it is. All that work
has been done for you by the implementers. Decades ago.
I just
did a quick test comparing complation times for an empty program
with no #include directives and an empty program with #include
directives for <stdint.h> and <inttypes.h>. The difference was
about 3 milliseconds. I quite literally could not care care less.
Doing stuff the C way requires LOTs of lines of code. Look at all
those MIN/MAX macros, the PRINT/SCAN macros; there's hundreds of them!
So what? I don't have to read those lines of code. All I have to read
is the standard (or some other document) that tells me how to use it.
On Thu, 20 Mar 2025 16:49:10 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
On Thu, 20 Mar 2025 16:14:54 -0000 (UTC)
Kaz Kylheku <643-408-1753@kylheku.com> wibbled:
On 2025-03-20, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote: >>>>> I guess some maths problems can't be proven directly, they have to be - >>for
want of a better word - run. A bit like the halting problem in CS.
The halting problem is a perfect example of a problem which *cannot* be >>>>proven by running anything.
So if you run the program and it halts that doesn't prove that it will halt?
Umm, ok.
If you run a program and it has NOT halted so far, you don't know
whether or not it halts. If it doesn't halt, you will wait forever. To
True, but you said it cannot be proven. What you meant was it cannot *always* be proven to halt.
On 20/03/2025 13:36, Scott Lurndal wrote:
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>>>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why
not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
Unix and Linux define it as 32 bits on 32-bit architectures and 64 bits
on 64-bit ones.
So long can't be used in programs intended to be portable to
other operating systems.
As defined by Unix/Linux, long is not portable between different
Unix/Linux OSes if they run on a different architecture.
As defined by Microsoft, long is portable between Windows OSes even on different architectures.
'long long' is defined as a 64-bit
type in both Windows and Linux.
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular
implementation. No useful implementation would fail to define
uint64_t in these modern times.
The problem with 'long' manifests itself there too, since on Linux,
'int64_t' appears to be commonly defined on top of 'long' for 32-bit
systems, and 'long long' for 64-bit ones.
bart <bc@freeuk.com> wrote:
On 20/03/2025 13:36, Scott Lurndal wrote:
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am >>>>>> sure about.
The width of char and [un]signed char must be at least 8 bits.
The width of [un]signed short must be at least 16 bits.
The width of [un]signed int must be at least 16 bits.
The width of [un]signed long must be at least 32 bits.
The width of [un]signed long long must be at least 64 bits.
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why >>>> not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values,
then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
Unix and Linux define it as 32 bits on 32-bit architectures and 64 bits
on 64-bit ones.
So long can't be used in programs intended to be portable to
other operating systems.
As defined by Unix/Linux, long is not portable between different
Unix/Linux OSes if they run on a different architecture.
It portably between 32 and 64 bit machines gives word-sized
integer type.
As defined by Microsoft, long is portable between Windows OSes even on
different architectures.
It gives 'long' different meaning than it had previously. And to
that matters rather useless meaning, as already 'int' gives 32
bit integers on bigger machines.
bart <bc@freeuk.com> wrote:
As defined by Unix/Linux, long is not portable between different
Unix/Linux OSes if they run on a different architecture.
It portably between 32 and 64 bit machines gives word-sized
integer type.
As defined by Microsoft, long is portable between Windows OSes even on
different architectures.
It gives 'long' different meaning than it had previously.
And to
that matters rather useless meaning, as already 'int' gives 32
bit integers on bigger machines.
'long long' is defined as a 64-bit<snip>
type in both Windows and Linux.
Using the defined width types is far better (e.g. uint64_t);
even if the standard allows the type to not exist on a particular
implementation. No useful implementation would fail to define
uint64_t in these modern times.
The problem with 'long' manifests itself there too, since on Linux,
'int64_t' appears to be commonly defined on top of 'long' for 32-bit
systems, and 'long long' for 64-bit ones.
You mixed up this: 'int64_t' is defined as 'long long' for 32-bit
systems and as 'long' for 64-bit ones.
Doing it as you wrote
would give you variable length type. Of course, if you need
word-sized integer in Windows you may define it as 'long' for 32-bit
Windows and as 'long long' for 64-bit ones.
bart <bc@freeuk.com> writes:
On 21/03/2025 01:47, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
You're complaining about how much work it is. All that work
has been done for you by the implementers. Decades ago.
We are talking about defining types like 'int32' on top of 'char short
int long', yes? Then how difficult could it possibly be?
If you want <stdint.h> and <inttypes.h> headers that work correctly with
all relevant compilers, it's not particularly easy. I'll note that the
MUSL implementation of <stdint.h> is 117 lines, compared to 308 for GNU
libc.
I just
did a quick test comparing complation times for an empty program
with no #include directives and an empty program with #include
directives for <stdint.h> and <inttypes.h>. The difference was
about 3 milliseconds. I quite literally could not care care less.
I'm sorry but that's a really poor attitude, with bad
consequences. You're saying it doesn't matter how complex a header or
set of headers is, even when out of proportion to the task.
But this is why we end up with such complicated headers.
Complicated headers that work.
[...\
I think your response clarifies matters. Nobody cares, even as
compilers grind to a halt under all preprocessing.
If compilers ground to a halt, I would certainly care. They don't.
Doing stuff the C way requires LOTs of lines of code. Look at allSo what? I don't have to read those lines of code. All I have to
those MIN/MAX macros, the PRINT/SCAN macros; there's hundreds of them!
read
is the standard (or some other document) that tells me how to use it.
It is crass. But it also affects the programmer because they have to
explicitly include that specific header and then remember the
dedicated MIN/MAX macros for the specific type. And they have to
/know/ the type.
Yes, of course.
If the type is opaque, or is an alias, then they won't know the name
of the macro. If the typedef is 'T' for example, then what's the macro
for its MAX value? Which header will they need?
There may not be one. For example, there's no format specifier for
time_t. If I need to print a time_t value, I'll probably cast to
intmax_t and use "%jd". If I'm being obsessive about portability, I'll
test whether time_t is signed, unsigned, or floating-point (all of which
are possible in principle), and use "%jd", "%ju", or "%Lf".
In a certain language I use, it will be T.max (and there are no
headers). I'm not suggesting that C turns into that language, only
that somebody acknowledges the downsides of using C's approach, since
again nobody cares.
I acknowledge the downsides of C's approach. See, all you had to
do was ask.
As Dennis Ritchie said, "C is quirky, flawed, and an enormous success".
It would be very nice if C had some kind of more generic I/O that
doesn't require remembering arbitrary format strings and qualifiers
for each type, and that doesn't provide format strings for a lot of
types in the standard library, and certainly not for types defined
in user code. And I'd *love* it if a future C standard removed
the undefined behavior for numeric input using *scanf(). Other C
programmers will have different priorities than yours or mine.
If I want to print a time_t value in C++, I just write
`std::cout << t` and the compiler figures out which overloaded
function to call.
Scripting languages like Perl and Python have
print functions that take arguments of arbitrary types, and ways
to interpolate numeric values into string literals. And so on.
I'm not sure what would be the best way to add something like this
in C202y or C203z. There are arguments against adding too many new
features to C when other languages are available; if C became C++
Lite, a lot of programmers would just use C++. There are a number
of different approaches that could be taken, and choosing among
them is not trivial.
When I talk about how to work with C as it's currently defined,
you tend to see advocacy where it doesn't exist. When you complain
about things in C that I don't think are real problems, you tend
to assume that I'm saying C is perfect, something I've never said.
When you ask why something in C is defined the way it is, you don't acknowledge when people take the time to explain it.
On 21/03/2025 17:51, Waldek Hebisch wrote:
bart <bc@freeuk.com> wrote:
As defined by Unix/Linux, long is not portable between different
Unix/Linux OSes if they run on a different architecture.
It portably between 32 and 64 bit machines gives word-sized
integer type.
Which was not its intention.
(Probably intptr_t or ssize_t is better for
that purpose, and will be portable between Windows and Linux.)
As defined by Microsoft, long is portable between Windows OSes even on
different architectures.
It gives 'long' different meaning than it had previously.
I explained the differences without necessarily saying one is better
than the other. Sometimes one is more more useful, sometimes the other.
And to
that matters rather useless meaning, as already 'int' gives 32
bit integers on bigger machines.
Well, 'long' is also useless on 32-bit Linux machines as it is the same
size as 'int'.
One 'con' for Linux' approach is when someone assumes 'long' is i32;
when they run code on 64 bits, it will either be wasteful, or it could
go badly wrong.
(I'm so glad I switched to all-64-bits in my own stuff, early last decade.
However lots of software has taken a long time to catch up. I acquired
an RPi 4 board 5 years ago with a view to doing 64-bit ARM development,
but most OSes were still 32 bits, and 64-bit ones immature. (You need a 64-bit OS to easily develop and run 64-bit programs.)
Even now, 32-bit OSes are supplied by default. I finally got a solid
64-bit OS for it last week. I just wondered what the point is of having 64-bit hardware if people just run 32-bit stuff on it.)
Sorry, but there's something wrong if you have to write all that to get
a handful of fixed-width types. (And if this is for a multitude of
targets, then there should be a dedicated header per target).
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part
of the core language, it would be zero lines.
On 2025-03-21, Waldek Hebisch <antispam@fricas.org> wrote:
bart <bc@freeuk.com> wrote:
On 20/03/2025 13:36, Scott Lurndal wrote:
bart <bc@freeuk.com> writes:
On 20/03/2025 12:09, Tim Rentsch wrote:
Michael S <already5chosen@yahoo.com> writes:
I suspected that, but was not sure, so suggested to DFS a type that I am
sure about.
The width of char and [un]signed char must be at least 8 bits. >>>>>> The width of [un]signed short must be at least 16 bits. >>>>>> The width of [un]signed int must be at least 16 bits. >>>>>> The width of [un]signed long must be at least 32 bits. >>>>>> The width of [un]signed long long must be at least 64 bits. >>>>>>
That should be easy enough to remember now.
That table suggests that any program mixing 'short' and 'int' is
suspect. If 'int' doesn't need to store values beyond 16 bits, then why >>>>> not use 'short'?
'long' is another troublesome one. If the need is for 32-bit values, >>>>> then it's surprisingly rare in source code.
Long is useless, because Microsoft made the mistake of defining
'long' as 32-bits on 64-bit architectures, while unix and linux
define it as 64-bits.
Unix and Linux define it as 32 bits on 32-bit architectures and 64 bits
on 64-bit ones.
So long can't be used in programs intended to be portable to
other operating systems.
As defined by Unix/Linux, long is not portable between different
Unix/Linux OSes if they run on a different architecture.
It portably between 32 and 64 bit machines gives word-sized
integer type.
The bitness of modern mainstream machines is their address size.
C99 gaves us address-sized integers: intptr_t and uintptr_t.
If you want a 64 bit type on a 64 bit system and 32 bit type
on a 32 bit system, use those.
(The problem is that idea observed in Unix-like environments that long
is expected to be address-sized precedes C99.)
As defined by Microsoft, long is portable between Windows OSes even on
different architectures.
It gives 'long' different meaning than it had previously. And to
that matters rather useless meaning, as already 'int' gives 32
bit integers on bigger machines.
In Microsoft land, there is a LONG type, which is involved in
the Win32 ABIs. That was their mistake.
In plenty of interfaces, Windows uses the types WORD and DWORD, which
are 16 and 32 bits wide unsigned types. (As well as QWORD,
a 64 bitter).
The problem is, when someone needed the signed versions of
WORD and DWORD, they found them to be missing, and stupidly came up with
the names INT and LONG (and derived typedefs like LPARAM).
Nobody caught this code smell and so it got woven into the Windows API. Probably long before 32 bit Windows, I'm guessing.
Thus, LONG has to continue to be a 32 bit type, since it is
used as a "signed DWORD".
But it's inconceivable for LONG to to be a typedef for anything other
than long. Too much code depends on the wrong idea that LONG and long
are interchangeable.
Thus long has to be stuck on 32 bits.
Since I've mostly used WinAPI via an FFI, I'm used to creating my own bindings and using my own aliases for this ttypes. (Mostly it comes down
to one of i32 i64 u32 u64 plus a pointer type.)
Thus long has to be stuck on 32 bits.
There really isn't much in it. Here's the evolution as I see it (I stand
to be corrected if necessary):
The point is that there was usually a size exactly double the width of
'int', but it become less necessary when 'int' reached 64 bits.
Muttley@DastardlyHQ.org writes:
But 99.99% of the time doesn't.
Famously, mathematician G.H. Hardy was a fan of number theory _because_
it seemed to have no 'real world' applications (i.e. applications
outside of mathematics itself). Eventually, of course, it became the >theoretical basis of public-key cryptography.
bart <bc@freeuk.com> writes:
On 21/03/2025 19:04, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 21/03/2025 01:47, Keith Thompson wrote:If you want <stdint.h> and <inttypes.h> headers that work correctly
bart <bc@freeuk.com> writes:
You're complaining about how much work it is. All that work
has been done for you by the implementers. Decades ago.
We are talking about defining types like 'int32' on top of 'char short >>>> int long', yes? Then how difficult could it possibly be?
with all relevant compilers, it's not particularly easy. I'll note
that the MUSL implementation of <stdint.h> is 117 lines, compared to
308 for GNU libc.
Complicated headers that work.I just did a quick test comparing complation times for an empty
program with no #include directives and an empty program with
#include directives for <stdint.h> and <inttypes.h>. The
difference was about 3 milliseconds. I quite literally could not
care care less.
I'm sorry but that's a really poor attitude, with bad
consequences. You're saying it doesn't matter how complex a header or
set of headers is, even when out of proportion to the task.
But this is why we end up with such complicated headers.
[...\
I think your response clarifies matters. Nobody cares, even asIf compilers ground to a halt, I would certainly care. They don't.
compilers grind to a halt under all preprocessing.
50 modules each including GTK.h say, which was 0.33Mloc across 500
headers (so reading 16Mloc and 25,000 headers in total when all are
compiled) would not impact your builds at all? OK.
First you talked about compilers grinding to a halt, then you talked
about headers not impacting builds at all. Those goalposts of yours
move *fast*.
For the record, as you can see above, I did not say that builds would
not be impacted. Do not put words into my mouth again.
printf("%v\n", t); # (used to be '?'; changed to 'v')
}
The compiler replaces the 'v' format with a conventional format code
according to the type of the expression. For my 'time_t', it happens
to be 'lld'.
That's nice. Seriously, it's nice. If it were added to a future
edition of the language, I'd likely use it (once I could count on it
being supported, which would take a while).
The Go language has something like that.
You can add extensions like that to your own compiler easily
enough. Adding them to the C standard (which requires getting all implementers to support them) is a lot harder. Does it work for
both output (printf) and input (scanf)? What if the format string
isn't a string literal; does the compiler generate code to adjust
it, allocating space for the translated string and deallocating it
after the call? Does it work with printf("%n", &var)? What about qualifiers, specifying width, base, and so forth.
an integer of arbitrary type in hexadecimal in a right-justified
8-digit zero-padded field? The feature implies an ability for
generic code that works with different types; can programmers use
that feature for things other than format strings? How much more
complicated would the C language (as distinct from the library)
have to be to support this?
If you have answers to all those questions, and to all the other
questions that haven't occurred to me, I wouldn't mind seeing
something like that in a future version of C. I haven't looked
closely at Go, but it's a compiled language with a feature similar
to what you describe; it could probably be mined for ideas.
Or maybe we should be thinking in terms of something other than format strings. The idea that "%v", which is a 3-byte chunk of data, has compile-time implications in certain contexts is a bit unnerving.
Ada chose the short name "Put" for its output routines.
It's overloaded, so you can write `Put(this); Put(that);
Put(the_other);` Maybe that a little too verbose, but how about
a new built-in operator that takes an argument of any of various
types and yields something that can be printed? '$' is available.
I haven't thought this through.
That's amazing.
Not particularly.
C has programmer-defined operator (and function)
overloading as a language feature. (There are IMHO some serious
flaws in C++'s use of overloaded "<<" for output, but I won't go
into that here.)
bart <bc@freeuk.com> wrote:
Sorry, but there's something wrong if you have to write all that to get
a handful of fixed-width types. (And if this is for a multitude of
targets, then there should be a dedicated header per target).
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part
of the core language, it would be zero lines.
You need few (say 3) lines of compiler code to define a type.
AFAICS there are 24 types in intXX... and uintXX... family.
So about 72 lines in compiler. For compatiblity with older
code you probably should define types under internal names
and have 24 lines in stdint.h (+3 lines of include guard).
stdint.h defines quite a bit more than just types, so actual
saving from having them built into compiler would be small,
in particular since preprocessor is fast. On my machine
I see 91 code lines after preprocessing of stdint.h. And
actually, several of definitions like '__pid_t' go beyond C
and are needed by other headers. So, really is not a big
deal.
BTW: I just tried
/tmp$ time gcc -E foo.c | wc
1000006 2000022 12889013
real 0m0.359s
user 0m0.351s
sys 0m0.085s
So gcc preprocessor is able to handle almost 3 million lines
per second. The lines were short, but gcc goes trough
piles of header files resonably fast, probably much faster
than you think.
I also tried to compile file contaning 100000 declarations
like:
extern int a0(void);
....
extern int a999999(void);
Compilation of such file takes 1.737s, so about 575000 lines
per second. So a lot of function declarations in header
files should not slow gcc too much.
On 3/18/2025 11:26 PM, Keith Thompson wrote:
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and write
output to standard output."
ha! It usually helps to read the instructions first.
The autotester expects your program to read arguments from stdin, not
from command line arguments.
It probably passes no arguments to your program, so argv[1] is a null
pointer. It's likely your program compiles (assuming the NBSP
characters were added during posting) and crashes at runtime,
producing no output.
I KNEW clc would come through!
Pretty easy fixes:
1 use scanf()
2 update int to long
3 handle special case of n = 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
bart <bc@freeuk.com> writes:
This is a C program using one of the extensions from my old compiler:
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = clock();
printf("%v\n", t); # (used to be '?'; changed to 'v')
}
The compiler replaces the 'v' format with a conventional format code
according to the type of the expression. For my 'time_t', it happens
to be 'lld'.
That's nice. Seriously, it's nice. If it were added to a future
edition of the language, I'd likely use it (once I could count on it
being supported, which would take a while).
It would be very nice if C had some kind of more generic I/O that
doesn't require remembering arbitrary format strings and qualifiers
for each type, and that doesn't provide format strings for a lot of
types in the standard library, and certainly not for types defined
in user code. And I'd *love* it if a future C standard removed
the undefined behavior for numeric input using *scanf(). Other C
programmers will have different priorities than yours or mine.
If I want to print a time_t value in C++, I just write
`std::cout << t` and the compiler figures out which overloaded
function to call.
That's amazing.
Not particularly. C has programmer-defined operator (and function)
overloading as a language feature. (There are IMHO some serious
flaws in C++'s use of overloaded "<<" for output, but I won't go
into that here.)
[...]
Here's my solution, for what it's worth:
#include <stdio.h>
unsigned long weird(unsigned long n)
{
printf("%lu", n);
if(n & 1)
{
/* Odd - multiply by 3 & add 1. */
n = n * 3 + 1;
}
else
{
/* Even - divide by 2. */
n /= 2;
On 21/03/2025 01:47, Keith Thompson wrote:
I just
did a quick test comparing complation times for an empty program
with no #include directives and an empty program with #include
directives for <stdint.h> and <inttypes.h>. The difference was
about 3 milliseconds. I quite literally could not care care less.
I'm sorry but that's a really poor attitude, with bad
consequences.
You're saying it doesn't matter how complex a header or
set of headers is, even when out of proportion to the task.
On 22/03/2025 02:37, Waldek Hebisch wrote:
bart <bc@freeuk.com> wrote:
Sorry, but there's something wrong if you have to write all that to get
a handful of fixed-width types. (And if this is for a multitude of
targets, then there should be a dedicated header per target).
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part
of the core language, it would be zero lines.
You need few (say 3) lines of compiler code to define a type.
AFAICS there are 24 types in intXX... and uintXX... family.
There's about 8, unless you include FAST/LEAST which are of interest to
a minority of the minority who are even aware of them.
So about 72 lines in compiler. For compatiblity with older
code you probably should define types under internal names
and have 24 lines in stdint.h (+3 lines of include guard).
It's a lot more than 72 lines in a compiler to support numeric types.
But this is about exposing fixed-size type aliases to existing types,
which can be done fairly tidily in a compiler,
but not as tidily as when
all the built-in types can be expressed as one token; some need multiple tokens.
Also C requires those aliases to be hidden unless a particular header is used.
Still, I was remarking on those Q8 headers requiring 1300 lines to add
these aliases.
stdint.h defines quite a bit more than just types, so actual
saving from having them built into compiler would be small,
in particular since preprocessor is fast. On my machine
I see 91 code lines after preprocessing of stdint.h. And
actually, several of definitions like '__pid_t' go beyond C
and are needed by other headers. So, really is not a big
deal.
BTW: I just tried
/tmp$ time gcc -E foo.c | wc
1000006 2000022 12889013
real 0m0.359s
user 0m0.351s
sys 0m0.085s
So gcc preprocessor is able to handle almost 3 million lines
per second. The lines were short, but gcc goes trough
piles of header files resonably fast, probably much faster
than you think.
Testing -E is tricky, since the output is textual, and usually
interspersed with # lines giving source line number info.
What was in foo.c?
In any case, I know that gcc can process headers reasonably fast
(otherwise it would take 10 seconds to plough through windows.h at the
speed of compiling code).
But it's the sheer size and scale of some headers that is the problem.
Why do you think precompiled headers were invented?
Compiling this program:
#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"
int main(){}
took gcc 0.85 seconds on my machine (however hello.c takes 0.2 seconds)
(SDL2 headers comprise 75 .h files and 50K lines; so about 75Kloc throughput.)
Compiling this program:
#include <windows.h>
int main(){}
took 1.36 seconds. window.h might comprise 100 or 165 unique headers,
with 100-200K unique lines of code; I forget.
These figures are for each module that uses those headers. (My bcc took
0.07 seconds for the SDL test. The windows.h test can't be compared as
my version of that header is much smaller.)
^^^^^^I also tried to compile file contaning 100000 declarations
like:
extern int a0(void);
....
extern int a999999(void);
Compilation of such file takes 1.737s, so about 575000 lines
per second. So a lot of function declarations in header
files should not slow gcc too much.
I get these results (the test file has 'int main(){}' at the end):
c:\c>tim gcc fred.c
Time: 4.832
c:\c>tim tcc fred.c
Time: 4.620
c:\c>tim bcc fred.c
Compiling fred.c to fred.exe
Time: 1.324
Bear in mind that both gcc/tcc are presumably optimised code; bcc isn't)
On 2025-03-22, bart <bc@freeuk.com> wrote:
The point is that there was usually a size exactly double the width of
'int', but it become less necessary when 'int' reached 64 bits.
Yes, because other than for masks of 128 bits, there isn't a whole
lot of stuff you can *count* for which you need such large integers.
Money?
In an accounting system, if you use signed 64 bits for pennies, you can
go to 9.2 x 10^16 dollars.
Large integers are needed for crypto and such, but then 128 isn't enough anyway.
Groovy hepcat DFS was jivin' in comp.lang.c on Wed, 19 Mar 2025 03:42
pm. It's a cool scene! Dig it.
On 3/18/2025 11:26 PM, Keith Thompson wrote:
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and write
output to standard output."
ha! It usually helps to read the instructions first.
The autotester expects your program to read arguments from stdin, not
from command line arguments.
It probably passes no arguments to your program, so argv[1] is a null
pointer. It's likely your program compiles (assuming the NBSP
characters were added during posting) and crashes at runtime,
producing no output.
I KNEW clc would come through!
Pretty easy fixes:
1 use scanf()
Normally I'd say take care with scanf(). But in this case, since the program is intended to be executed in an automated environment, it
should be fine.
The reason scanf() can be a bit iffy is that you can't control what a
user will enter. If you search Google or Duck Duck Go for "comp.lang.c
faq" you can find more information on this and other issues. (The FAQ
is still out there, people..., somewhere...)
2 update int to long
3 handle special case of n = 1
The problem definition doesn't mention any special case. You should, I think, treat 1 like any other number. So the output for 1 should be
1 4 2 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
Yep, that's a more usual approach.
Another suggestion I have is to use a separate function to do part of
the work. But it's not vital.
Also, since the specification says that only positive numbers are to
be accepted, it makes sense (to me, at least) to use an unsigned type
for n.
One more thing: using while(1){...break;} is a bit pointless. You can
use do{...}while(1 != n) instead.
Here's my solution, for what it's worth:
#include <stdio.h>
unsigned long weird(unsigned long n)
{
printf("%lu", n);
if(n & 1)
{
/* Odd - multiply by 3 & add 1. */
n = n * 3 + 1;
}
else
{
/* Even - divide by 2. */
n /= 2;
}
return n;
}
int main(void)
{
unsigned long n;
/* Get n from stdin. */
scanf("%lu", &n);
/* Now feed it to the algorithm. */
do
{
n = weird(n);
putchar(' ');
} while(1 != n);
printf("%lu\n", n);
return 0;
}
bart <bc@freeuk.com> wrote:
On 21/03/2025 17:51, Waldek Hebisch wrote:
bart <bc@freeuk.com> wrote:
(Probably intptr_t or ssize_t is better for
that purpose, and will be portable between Windows and Linux.)
Those did not exist in 1991 and would be needed only for small
machines. Except for Microsoft which decided to push its own,
different way.
One 'con' for Linux' approach is when someone assumes 'long' is i32;
when they run code on 64 bits, it will either be wasteful, or it could
go badly wrong.
One 'con' of any assumption is that somebody can make a different
assumption.
Programmers shouldn't be making 'assumptions' in the first place.
The architectural ABI describes fully the capabilities of the
native types. If the programmer isn't aware of that, they
shouldn't be programming.
Groovy hepcat DFS was jivin' in comp.lang.c on Wed, 19 Mar 2025 03:42
pm. It's a cool scene! Dig it.
On 3/18/2025 11:26 PM, Keith Thompson wrote:
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and write
output to standard output."
ha! It usually helps to read the instructions first.
The autotester expects your program to read arguments from stdin, not
from command line arguments.
It probably passes no arguments to your program, so argv[1] is a null
pointer. It's likely your program compiles (assuming the NBSP
characters were added during posting) and crashes at runtime,
producing no output.
I KNEW clc would come through!
Pretty easy fixes:
1 use scanf()
Normally I'd say take care with scanf(). But in this case, since the
program is intended to be executed in an automated environment, it
should be fine.
The reason scanf() can be a bit iffy is that you can't control what a
user will enter. If you search Google or Duck Duck Go for "comp.lang.c
faq" you can find more information on this and other issues. (The FAQ
is still out there, people..., somewhere...)
2 update int to long
3 handle special case of n = 1
The problem definition doesn't mention any special case. You should, I
think, treat 1 like any other number. So the output for 1 should be
1 4 2 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
Yep, that's a more usual approach.
Another suggestion I have is to use a separate function to do part of
the work. But it's not vital.
Also, since the specification says that only positive numbers are to
be accepted, it makes sense (to me, at least) to use an unsigned type
for n.
One more thing: using while(1){...break;} is a bit pointless. You can
use do{...}while(1 != n) instead.
Here's my solution, for what it's worth:
And here's mine.
int
main(int argc, const char **argv)
{
unsigned int n;
scanf("%u", &n);
printf("%u ", n);
do {
n = (n & 1u) ? n * 3u + 1u : n >> 1u;
printf("%u ", n);
} while (n != 1u);
putchar('\n');
return 0;
}
bart <bc@freeuk.com> wrote:
On 22/03/2025 02:37, Waldek Hebisch wrote:
bart <bc@freeuk.com> wrote:
Sorry, but there's something wrong if you have to write all that to get >>>> a handful of fixed-width types. (And if this is for a multitude of
targets, then there should be a dedicated header per target).
GCC's stdint.h is 200 lines. Mine is 75 lines. It these types were part >>>> of the core language, it would be zero lines.
You need few (say 3) lines of compiler code to define a type.
AFAICS there are 24 types in intXX... and uintXX... family.
There's about 8, unless you include FAST/LEAST which are of interest to
a minority of the minority who are even aware of them.
Well, FAST/LEAST types are mandatory for standard compliance.
So about 72 lines in compiler. For compatiblity with older
code you probably should define types under internal names
and have 24 lines in stdint.h (+3 lines of include guard).
It's a lot more than 72 lines in a compiler to support numeric types.
But this is about exposing fixed-size type aliases to existing types,
which can be done fairly tidily in a compiler,
Yes, there is complex machinery to support types and compiler
data structires in general. But once machinery is in place
you need to create type node and insert it into symbol table.
In gcc creation of type node may look like:
sizetype = make_node (INTEGER_TYPE);
TYPE_NAME (sizetype) = get_identifier ("sizetype");
TYPE_PRECISION (sizetype) = precision;
TYPE_UNSIGNED (sizetype) = 1;
scalar_int_mode mode = smallest_int_mode_for_size (precision);
SET_TYPE_MODE (sizetype, mode);
SET_TYPE_ALIGN (sizetype, GET_MODE_ALIGNMENT (TYPE_MODE (sizetype)));
TYPE_SIZE (sizetype) = bitsize_int (precision);
TYPE_SIZE_UNIT (sizetype) = size_int (GET_MODE_SIZE (mode));
set_min_and_max_values_for_integral_type (sizetype, precision, UNSIGNED);
But such things are repeated for several types, so one can have
function like 'create_integer_type_node' which is doing the above,
but for type name and precision which are arguments to the function.
Of course, if you need to do soemthing special to a type, then
you may need a lot of code. But integer types should be handled
anyway, so there is really no special code beyond what is already
there.
but not as tidily as when
all the built-in types can be expressed as one token; some need multiple
tokens.
Unlike classic integer types, types in stdint.h have names which
are single token, so all you need to do is to insert entry in the
symbol table.
^^^^^^I also tried to compile file contaning 100000 declarations
Oops, should be 1000000.
like:
extern int a0(void);
....
extern int a999999(void);
Compilation of such file takes 1.737s, so about 575000 lines
per second. So a lot of function declarations in header
files should not slow gcc too much.
I get these results (the test file has 'int main(){}' at the end):
c:\c>tim gcc fred.c
Time: 4.832
c:\c>tim tcc fred.c
Time: 4.620
c:\c>tim bcc fred.c
Compiling fred.c to fred.exe
Time: 1.324
Bear in mind that both gcc/tcc are presumably optimised code; bcc isn't)
On my machine tcc preprocesses probably about 20% faster than gcc.
For timing compilation I used 'gcc -c' to generate linkable object
file, so no need to have 'main'.
When actually compilning on my
machine tcc is significantly faster, on the same file 'tcc -c'
takes 0.418s, so more than 4 times faster than 'gcc -c'.
I do not know why 'tcc' is that much faster.
One possibility
is that 'gcc' contains various extra info in compiler data
structures that help when optimizing, but require extra effort
even when not optimiziong.
antispam@fricas.org (Waldek Hebisch) writes:
bart <bc@freeuk.com> wrote:
On 21/03/2025 17:51, Waldek Hebisch wrote:
bart <bc@freeuk.com> wrote:
(Probably intptr_t or ssize_t is better for
that purpose, and will be portable between Windows and Linux.)
Those did not exist in 1991 and would be needed only for small
machines. Except for Microsoft which decided to push its own,
different way.
ssize_t existed in before 1990 (in SVR4). intptr_t came later.
$ grep ssize_t common/head/*
common/head/aio.h: ssize_t aio__return; /* operation result value */
common/head/unistd.h:extern ssize_t read(int, void *, size_t); common/head/unistd.h:extern ssize_t write(int, const void *, size_t);
One 'con' for Linux' approach is when someone assumes 'long' is i32;
when they run code on 64 bits, it will either be wasteful, or it could
go badly wrong.
One 'con' of any assumption is that somebody can make a different
assumption.
Programmers shouldn't be making 'assumptions' in the first place.
The architectural ABI describes fully the capabilities of the
native types. If the programmer isn't aware of that, they
shouldn't be programming.
bart <bc@freeuk.com> writes:
On 20/03/2025 19:10, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
stdint.h et al are just ungainly bolt-ons, not fully supported by theNo, they're fully supported by the language. They've been in the ISO
language.
standard since 1999.
I don't think so. They are add-ons that could have been created in
user-code even prior to C99 (user-defined typedefs for 64 bits would
'need long long').
Sure, they could; see Doug Gwyn's q8, for example.
All that's happened is that 'stdint.h' has been blessed.
I.e., it was made part of the language, specifically the standard
library that's part of the language standard. Which is what I said,
but for some reason you disagreed.
Yes, the format specifiers are a bit awkward. Boo hoo.
On 22/03/2025 08:07, Peter 'Shaggy' Haywood wrote:
<snip>
Here's my solution, for what it's worth:
#include <stdio.h>
unsigned long weird(unsigned long n)
{
printf("%lu", n);
if(n & 1)
{
/* Odd - multiply by 3 & add 1. */
n = n * 3 + 1;
Or you can save yourself a multiplication
n = (n << 2) - (n - 1);
potentially shaving entire picoseconds off the runtime.
}
else
{
/* Even - divide by 2. */
n /= 2;
do
{
n >>= 1;
} while(~(n & 1));
...and there goes another attosecond.
Peter 'Shaggy' Haywood <phaywood@alphalink.com.au> writes:
Groovy hepcat DFS was jivin' in comp.lang.c on Wed, 19 Mar 2025 03:42
pm. It's a cool scene! Dig it.
On 3/18/2025 11:26 PM, Keith Thompson wrote:
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and
write output to standard output."
ha! It usually helps to read the instructions first.
The autotester expects your program to read arguments from stdin,
not from command line arguments.
It probably passes no arguments to your program, so argv[1] is a
null pointer. It's likely your program compiles (assuming the
NBSP characters were added during posting) and crashes at runtime,
producing no output.
I KNEW clc would come through!
Pretty easy fixes:
1 use scanf()
Normally I'd say take care with scanf(). But in this case, since
the
program is intended to be executed in an automated environment, it
should be fine.
The reason scanf() can be a bit iffy is that you can't control
what a
user will enter. If you search Google or Duck Duck Go for
"comp.lang.c faq" you can find more information on this and other
issues. (The FAQ is still out there, people..., somewhere...)
2 update int to long
3 handle special case of n = 1
The problem definition doesn't mention any special case. You
should, I
think, treat 1 like any other number. So the output for 1 should be
1 4 2 1
4 instead of collecting the results in a char variable, I print
them as they're calculated
Yep, that's a more usual approach.
Another suggestion I have is to use a separate function to do part
of
the work. But it's not vital.
Also, since the specification says that only positive numbers are
to
be accepted, it makes sense (to me, at least) to use an unsigned type
for n.
One more thing: using while(1){...break;} is a bit pointless. You
can
use do{...}while(1 != n) instead.
Here's my solution, for what it's worth:
And here's mine.
int
main(int argc, const char **argv)
{
unsigned int n;
scanf("%u", &n);
printf("%u ", n);
do {
n = (n & 1u) ? n * 3u + 1u : n >> 1u;
printf("%u ", n);
} while (n != 1u);
putchar('\n');
return 0;
}
Or you can save yourself a multiplication
n = (n << 2) - (n - 1);
potentially shaving entire picoseconds off the runtime.
On Sat, 22 Mar 2025 13:25:43 +0000
Richard Heathfield <rjh@cpax.org.uk> wrote:
Or you can save yourself a multiplication
n = (n << 2) - (n - 1);
potentially shaving entire picoseconds off the runtime.
Unlikely.
More likely, your transformation will confuse compiler into generation
of suboptmal code.
Richard Heathfield <rjh@cpax.org.uk> writes:[...]
On 20/03/2025 13:06, Tim Rentsch wrote:
The C99 standard has a list of 54 what it calls "major changes",
although IMO many or most of those are fairly minor. There are
also other differences relative to C90, but most of them are
simply clarifications or slight changes in wording.
Those I largely recall from discussions at the time, but I dare
to conclude that your lack of a reference to C11, C17, and C23
means that they had a lesser effect on the language than I'd
feared.
[...]
As it turn out, the C11 standard lists only 15 "major changes" (if
my quick counting is correct), so your conclusion that later
versions have had a lesser effect appears to be correct, at least as
far as C11 goes. If I have time I may post again on this topic,
doing for the C11 standard what I did for the C99 standard.
bart <bc@freeuk.com> writes:
On 22/03/2025 03:50, Keith Thompson wrote:[...]
bart <bc@freeuk.com> writes:
On 21/03/2025 19:04, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
First you talked about compilers grinding to a halt, then you talkedI think your response clarifies matters. Nobody cares, even asIf compilers ground to a halt, I would certainly care. They don't.
compilers grind to a halt under all preprocessing.
50 modules each including GTK.h say, which was 0.33Mloc across 500
headers (so reading 16Mloc and 25,000 headers in total when all are
compiled) would not impact your builds at all? OK.
about headers not impacting builds at all. Those goalposts of yours
move *fast*.
You missed the "?".
No, I didn't. You insinuated that I had implied that large headers
would not impact builds. You phrased it as if you were questioning
something I had said. I don't care to debate this specific issue
further, but please be mmore careful.
For the record, as you can see above, I did not say that builds would
not be impacted. Do not put words into my mouth again.
Let me ask it again: so ploughing through a third of a million lines
of code across hundreds of #includes, even at the faster throughput
compared with compiling code, for a module of a few hundred lines,
will have little impact?
How about a project with 50 or 100 modules, each using that big
header, that needs to be built from scratch?
I don't know. I haven't taken the time to measure the impact,
and if I did there wouldn't be much I could do about it. It hasn't particularly inconvenienced me.
Most of the builds I do from source are straightforward. The general
pattern is roughly "configure;make;sudo make install". I have
a wrapper script that does that, figures out what arguments to
pass, adds some extra options, and so forth. I'm aware configures
scripts can be very large (the one for coreutils close to 95,000
lines), but I really don't care or see why I should. It works.
Building coreutils and installing 9.6 on my system took about 5
minutes, during which I was able to go off and do other things.
Could the whole thing be streamlined? Could a new version of the
autotools be developed that doesn't cater as much to obsolete systems
and generates smaller configure scripts? Would it substantially
improve build times? Quite possibly, but I'm not likely to be the
one to work about the details (unless someone wants to hire me to
look into it).
[...]
So let me ask /this/ again: if such a library consisted of ONE compact
header file, would it make the process simpler? Would it make
compilation of multiple modules faster?)
I don't know.
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are going
on to deal with it. Compilation speed for developers is always an
issue. There is a general movement away from LLVM-based backends
/because/ it is so slow.
Here is my summary of the corresponding list in the C11 standard
(descriptive headings reprepresent my own views on each area):
On Thu, 20 Mar 2025 17:29:22 +0200
Michael S <already5chosen@yahoo.com> wibbled:
Then how exactly do you printf value of type int64_t in a code that >expected to pass [gcc] compilation with no warnings on two platforms,
one of which is 64-bit Unix/Linux and another is just about anything
else?
Just use %llu everywhere. Warnings only matter if they're important
ones.
On 22/03/2025 23:46, Tim Rentsch wrote:
Here is my summary of the corresponding list in the C11 standard (descriptive headings reprepresent my own views on each area):
Thank you, Tim. What I'm taking away from this is that I'm not
personally affected by the changes. The getsectomy is a welcome
surprise, and the rest I can safely ignore.
No doubt others will appreciate your summary for other reasons,
so I've scribbled them down locally. Thanks again.
bart <bc@freeuk.com> writes:
This is a C program using one of the extensions from my old
compiler:
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = clock();
printf("%v\n", t); # (used to be '?'; changed to
'v') }
The compiler replaces the 'v' format with a conventional format code according to the type of the expression. For my 'time_t', it happens
to be 'lld'.
That's nice. Seriously, it's nice. If it were added to a future
edition of the language, I'd likely use it (once I could count on it
being supported, which would take a while).
The Go language has something like that.
You can add extensions like that to your own compiler easily
enough. Adding them to the C standard (which requires getting all implementers to support them) is a lot harder. Does it work for
both output (printf) and input (scanf)?
What if the format string
isn't a string literal; does the compiler generate code to adjust
it, allocating space for the translated string and deallocating it
after the call? Does it work with printf("%n", &var)? What about qualifiers, specifying width, base, and so forth. How do I print
an integer of arbitrary type in hexadecimal in a right-justified
8-digit zero-padded field? The feature implies an ability for
generic code that works with different types; can programmers use
that feature for things other than format strings? How much more
complicated would the C language (as distinct from the library)
have to be to support this?
If you have answers to all those questions, and to all the other
questions that haven't occurred to me, I wouldn't mind seeing
something like that in a future version of C. I haven't looked
closely at Go, but it's a compiled language with a feature similar
to what you describe; it could probably be mined for ideas.
Or maybe we should be thinking in terms of something other than format strings. The idea that "%v", which is a 3-byte chunk of data, has compile-time implications in certain contexts is a bit unnerving.
Ada chose the short name "Put" for its output routines.
It's overloaded, so you can write `Put(this); Put(that);
Put(the_other);` Maybe that a little too verbose, but how about
a new built-in operator that takes an argument of any of various
types and yields something that can be printed? '$' is available.
I haven't thought this through.
Apart from removal of gets() and not going into numerics for sake of
brevity, C11 has several useful additions to "old" library stuff, some
long overdue.
On 23/03/2025 08:50, Michael S wrote:
On Sun, 23 Mar 2025 01:34:54 +0000
bart <bc@freeuk.com> wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are
going on to deal with it. Compilation speed for developers is
always an issue. There is a general movement away from LLVM-based
backends /because/ it is so slow.
What "general movement" are you talking about?
I can't recollect any new* language for general-purpose computers
that is used by more than dozen* persons which is not based on LLVM
back end. Despite its undeniable slowness.
There's Rust + Cranelift:
"The goal of this project is to create an alternative codegen backend
for the rust compiler based on Cranelift. This has the potential to
improve compilation times in debug mode."
There's Go which was never based on LLVM:
"At the beginning of the project we considered using LLVM for gc but
decided it was too large and slow to meet our performance goals."
('gc' is 'Go Compiler'. Maybe Go is older than 15 years?
Still, LLVM
seems to have been around
and was thought to be slow then.)
And there's Zig:
https://news.ycombinator.com/item?id=39154513
There are other's comments:
"LLVM used to be hailed as a great thing, but with language projects
such as Rust, Zig and others complaining it's bad and slow and
they're moving away from it – how bad is LLVM really?"
Here's is a random quote from Reddit:
"2 minutes is really good for a full build. 2 minutes is pretty bad
for a one line change.
I also quit my job recently because of their terrible infrastructure.
All home-grown of course. A horrible mess of Python, C++ and Make.
So demotivating. And nobody except me cared."
TBH, for me 2 minutes would be really terrible even for a full build.
So would 2 seconds! (How big was this executable?)
On Sun, 23 Mar 2025 01:34:54 +0000
bart <bc@freeuk.com> wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are going
on to deal with it. Compilation speed for developers is always an
issue. There is a general movement away from LLVM-based backends
/because/ it is so slow.
What "general movement" are you talking about?
I can't recollect any new* language for general-purpose computers that
is used by more than dozen* persons which is not based on LLVM back end. Despite its undeniable slowness.
Muttley@DastardlyHQ.org writes:
In fact, i would suggest that it's increasingly difficult to find
non-recent mathematics that _hasn't_ found direct or non-direct 'real
world' applications.
The history of developments in mathematics suggests that your "99.99%"
claim is significantly incorrect. (If you'd said, say, "9.99%", my
internal reaction would have been "Hm, i guess that might be the case.")
All that said, i've lurked long enough in this group to know that trying
to have a good-faith conversation with you is pointless; i was mainly
On 3/18/2025 8:38 PM, DFS wrote:
I'm doing these algorithm problems at
https://cses.fi/problemset/list/
For instance: Weird Algorithm
https://cses.fi/problemset/task/1068
My code works fine locally (prints the correct solution to the
console), but when I submit the .c file the auto-tester flags it with
'runtime error' and says the output is empty.
------------------------------------------------------------
// If n is even, divide it by two.
// If n is odd, multiply it by three and add one.
// Repeat until n is one.
// n = 3: output is 3 10 5 16 8 4 2 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int n = atoi(argv[1]);
int len = 0;
char result[10000] = "";
sprintf(result, "%d ", n);
while(1) {
if((n % 2) == 0)
{n /= 2;}
else
{n = (n * 3) + 1;}
if(n != 1)
{
len = strlen(result);
sprintf(result + len, "%d ", n);
}
else
break;
}
len = strlen(result);
sprintf(result + len, "1 ");
printf("%s\n",result);
return 0;
}
------------------------------------------------------------
Any ideas?
Thanks
strdup.
https://www.geeksforgeeks.org/strdup-strdndup-functions-c/
Lynn
On Thu, 20 Mar 2025 15:55:21 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
On Thu, 20 Mar 2025 17:29:22 +0200
Michael S <already5chosen@yahoo.com> wibbled:
Then how exactly do you printf value of type int64_t in a code that
expected to pass [gcc] compilation with no warnings on two platforms,
one of which is 64-bit Unix/Linux and another is just about anything
else?
Just use %llu everywhere. Warnings only matter if they're important
ones.
Unimportant warnings matter a lot, because they make seeing
important warnings so much harder.
On 22/03/2025 23:46, Tim Rentsch wrote:
Here is my summary of the corresponding list in the C11 standard
(descriptive headings reprepresent my own views on each area):
Thank you, Tim. What I'm taking away from this is that I'm not
personally affected by the changes.
No doubt others will appreciate your summary for other reasons, so
I've scribbled them down locally. Thanks again.
Michael S <already5chosen@yahoo.com> writes:
On Fri, 21 Mar 2025 20:50:51 -0700
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
bart <bc@freeuk.com> writes:
This is a C program using one of the extensions from my old
compiler:
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = clock();
printf("%v\n", t); # (used to be '?'; changed
to 'v') }
The compiler replaces the 'v' format with a conventional format
code according to the type of the expression. For my 'time_t',
it happens to be 'lld'.
That's nice. Seriously, it's nice. If it were added to a future
edition of the language, I'd likely use it (once I could count on
it being supported, which would take a while).
The Go language has something like that.
You can add extensions like that to your own compiler easily
enough. Adding them to the C standard (which requires getting all
implementers to support them) is a lot harder. Does it work for
both output (printf) and input (scanf)?
That's the easiest question. And the right answer is "No, it does
not."
I was asking about bart's language extension. Do you have inside
information about that?
[...]
In theory, printf extension that is a little less nice than Bart's,
but close, can be developed in C23 with no additional core language features.
printf("%v\n", _TYIX(t));
Where _TYIX defined as
#define _TYIX(x) typeof_unqual((x)), (x)
In practice, it seems that C23 Standard does not say enough about
return value of typeof_unqual to make it feasible. Or, may be, my
source of information (en.cppreference.com/w/c/language/typeof)
is not up to date.
I don't see how that would work. typeof_unqual doesn't have a return
value; it yields a type, and can be used as a type name in a
declaration. Unless I've missed something big, C23 doesn't let you
pass a type name as a function argument.
Richard Heathfield <rjh@cpax.org.uk> writes:
On 22/03/2025 23:46, Tim Rentsch wrote:
Here is my summary of the corresponding list in the C11 standard
(descriptive headings reprepresent my own views on each area):
Thank you, Tim. What I'm taking away from this is that I'm not
personally affected by the changes.
I had a similar reaction when C99 came out. In fact it was several
years before I started looking at C99 as a suitable alternative to
using just C90. Gradually I began to see that the new features of
C99 offered substantial advantages over what C90 offers. My
impression is the C community at large followed a similar timeline.
For C11 I am somewhere in the middle. Most of the time I find C99
adequate, and don't need the capabilities added in C11; so C99 is
still my default choice, with C11 being the exception. However,
for building software libraries rather than just programs, C11
allows some significant benefits, so I am turning more and more
to C11 as I add functionality to the library projects I'm working
on. (I should add that I try to write code that can benefit from
C11 but still can be called from C99 or C90, perhaps with reduced functionality.)
It's strange: in one part of the computing world, the speed of building software is a very big deal. All sorts of efforts are going on to deal
with it. Compilation speed for developers is always an issue. There is a general movement away from LLVM-based backends /because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total non-issue!
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are going
on to deal with it. Compilation speed for developers is always an
issue. There is a general movement away from LLVM-based backends /
because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total
non-issue!
You find it strange that different parts of the computing world (or,
more appropriately, software development world) have different
priorities, needs and focuses for their tools? I find it very strange
that anyone would find that strange!
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are going
on to deal with it. Compilation speed for developers is always an
issue. There is a general movement away from LLVM-based backends /
because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total
non-issue!
You find it strange that different parts of the computing world (or,
more appropriately, software development world) have different
priorities, needs and focuses for their tools? I find it very strange
that anyone would find that strange!
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are
going on to deal with it. Compilation speed for developers is
always an issue. There is a general movement away from LLVM-based
backends / because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a
total non-issue!
You find it strange that different parts of the computing world
(or, more appropriately, software development world) have
different priorities, needs and focuses for their tools? I find
it very strange that anyone would find that strange!
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Do you know what the people in comp.lang.c have in common?
We program in C.
Do you know /why/ people program in C?
There can be many reasons, but a very common one is that they want
fast resulting binaries. Most serious programmers are familiar with
more than one language, and pretty much all other languages are
higher level, easier, and have higher developer productivity than C -
but the resulting binaries are almost always slower.
C programmers are typically not bothered about build times because a)
their build times are rarely high (Scott's projects are C++), and b),
they are willing to sacrifice high build times if it means more
efficient run times.
On 24/03/2025 15:07, bart wrote:
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Do you know what the people in comp.lang.c have in common?
We program in C.
Do you know /why/ people program in C?
There can be many reasons, but a very common one is that they want fast >resulting binaries. Most serious programmers are familiar with more
than one language, and pretty much all other languages are higher level, >easier, and have higher developer productivity than C - but the
resulting binaries are almost always slower.
C programmers are typically not bothered about build times because a)
their build times are rarely high (Scott's projects are C++), and b),
they are willing to sacrifice high build times if it means more
efficient run times.
On Mon, 24 Mar 2025 15:32:32 +0100
David Brown <david.brown@hesbynett.no> wibbled:
On 24/03/2025 15:07, bart wrote:
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Do you know what the people in comp.lang.c have in common?
We program in C.
Do you know /why/ people program in C?
There can be many reasons, but a very common one is that they want
fast resulting binaries. Most serious programmers are familiar with
more than one language, and pretty much all other languages are
higher level, easier, and have higher developer productivity than C
- but the resulting binaries are almost always slower.
C programmers are typically not bothered about build times because
a) their build times are rarely high (Scott's projects are C++), and
b), they are willing to sacrifice high build times if it means more >efficient run times.
I'm not sure what kind of build time he's looking for either. On this
Mac ARM laptop I can compile a 7600 line utility I wrote in C in 0.8
seconds real time, and that is using a makefile with 18 seperate
source files and a header and includes link time. So unless he's
rebuilding the linux kernel every day I don't see what the problem is.
loki$ ls *.c *.h | wc -l
19
loki$ wc -l *.c *.h
:
:
691 globals.h
7602 total
loki$ time make
:
:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
C programmers are typically not bothered about build times because a)
their build times are rarely high (Scott's projects are C++), and b),
they are willing to sacrifice high build times if it means more
efficient run times.
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are going
on to deal with it. Compilation speed for developers is always an
issue. There is a general movement away from LLVM-based backends /
because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total
non-issue!
You find it strange that different parts of the computing world (or,
more appropriately, software development world) have different
priorities, needs and focuses for their tools? I find it very strange
that anyone would find that strange!
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Even though one or two (like Scott Lurndal) had reported significant
build times (even you had remarked on it and made suggestions), but that
was brushed off.
I don't know; maybe with fast builds, people would have to do more work >instead of taking a coffee break!
On Mon, 24 Mar 2025 15:00:17 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
You would illustrate you point better if you run 'time make -B'.
On Mon, 24 Mar 2025 15:32:32 +0100
David Brown <david.brown@hesbynett.no> wibbled:
On 24/03/2025 15:07, bart wrote:
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Do you know what the people in comp.lang.c have in common?
We program in C.
Do you know /why/ people program in C?
There can be many reasons, but a very common one is that they want fast
resulting binaries. Most serious programmers are familiar with more
than one language, and pretty much all other languages are higher level,
easier, and have higher developer productivity than C - but the
resulting binaries are almost always slower.
C programmers are typically not bothered about build times because a)
their build times are rarely high (Scott's projects are C++), and b),
they are willing to sacrifice high build times if it means more
efficient run times.
I'm not sure what kind of build time he's looking for either. On this Mac
ARM laptop I can compile a 7600 line utility I wrote in C in 0.8 seconds
real time, and that is using a makefile with 18 seperate source files and
a header and includes link time. So unless he's rebuilding the linux kernel every day I don't see what the problem is.
loki$ ls *.c *.h | wc -l
19
loki$ wc -l *.c *.h
:
:
691 globals.h
7602 total
loki$ time make
:
:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
On 24/03/2025 16:17, Muttley@DastardlyHQ.org wrote:
*GASP*! 12 whole seconds! How can you cope with your day being interrupted >> like that for so long!
So applying your 100:1 ratio, you'd spend 20 whole minutes pondering
your next move before compiling again?
When you have near-instant build times then it's completely different
way of working.
Do you think people who work with scripting languages (or even writing
HTML) would tolerate an exasperating 12-second day between hitting Run,
and their test-run starting?
In the case of this project, development is incremental: run a test,
there's an opcode not yet done, add the lines for it, test it again.
Or do a timing test, measure, tweak a line to two, time it again to see
if it's any better.
Or there might be bunch of configuration and debug settings, that don't >warrant dedicated CLI options, so to change a setting means changing one
line and rebuilding. Why not? It only takes an instant!
If I had to wait 10+ seconds each time then it would both take all
fucking day AND drive me around the bend.
You really haven't got a clue.
On Mon, 24 Mar 2025 16:02:57 +0000
bart <bc@freeuk.com> wibbled:
On 24/03/2025 15:00, Muttley@DastardlyHQ.org wrote:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
So, your throughput is a whopping 9.5K lines/second?
On a tired laptop with multiple files it seems pretty good to me.
Build time is 1/15th of a second, for about 30K lines (so 450Klps). But
I also want to compile this via C, to take advantage of gcc's superior
optimiser. So first I transpile to C (that's also under 70ms):
I'll paraphrase someone elses point - who fucking cares? If you need lightning
fast compilation because you're constantly rebuilding your shit code to see if
it'll even compile never mind work then that says a lot about you as a dev.
The thinking/writing to compilation time ratio I imagine with most devs would probably be a minimum of 100 - 1, possibly much larger
The generated C file is 38Kloc, and takes 12 seconds. It takes nearly
TWO HUNDRED TIMES longer to build.
*GASP*! 12 whole seconds! How can you cope with your day being interrupted like that for so long!
On 24/03/2025 15:00, Muttley@DastardlyHQ.org wrote:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
So, your throughput is a whopping 9.5K lines/second?
Build time is 1/15th of a second, for about 30K lines (so 450Klps). But
I also want to compile this via C, to take advantage of gcc's superior >optimiser. So first I transpile to C (that's also under 70ms):
The generated C file is 38Kloc, and takes 12 seconds. It takes nearly
TWO HUNDRED TIMES longer to build.
I can tolerate that from time to time,
When you have near-instant build times then it's completely different
way of working.
Do you think people who work with scripting languages (or even writing
HTML) would tolerate an exasperating 12-second day between hitting Run,
and their test-run starting?
On Mon, 24 Mar 2025 15:32:32 +0100
David Brown <david.brown@hesbynett.no> wrote:
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of
building software is a very big deal. All sorts of efforts are
going on to deal with it. Compilation speed for developers is
always an issue. There is a general movement away from LLVM-based
backends / because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a
total non-issue!
You find it strange that different parts of the computing world
(or, more appropriately, software development world) have
different priorities, needs and focuses for their tools? I find
it very strange that anyone would find that strange!
What was strange was that that one view was shared by pretty much
everyone in comp.lang.c.
Do you know what the people in comp.lang.c have in common?
We program in C.
Do you know /why/ people program in C?
There can be many reasons, but a very common one is that they want
fast resulting binaries. Most serious programmers are familiar with
more than one language, and pretty much all other languages are
higher level, easier, and have higher developer productivity than C -
but the resulting binaries are almost always slower.
I disagree.
35-36 years ago I forgot about Pascal after few months of exposure to C.
It didn't happen because of speed of resulting binaries, but due to my
own improved productivity.
Ada and Rust are two other exampled of languages that lag behinds C in productivity.
And in all three cases above I still did not leave the realm of
relatively good languages. Unfortunately, I have to use at least one
bad language as well - tcl.
On Mon, 24 Mar 2025 16:49:35 +0000
bart <bc@freeuk.com> wibbled:
On 24/03/2025 16:17, Muttley@DastardlyHQ.org wrote:
*GASP*! 12 whole seconds! How can you cope with your day being interrupted >>> like that for so long!
So applying your 100:1 ratio, you'd spend 20 whole minutes pondering
your next move before compiling again?
No, because unlike you I understand the concept of splitting into modules
and having a makefile that just rebuilds whats changed, not the entire codebase.
When you have near-instant build times then it's completely different
way of working.
No it isn't. THat example I gave you built in 0.8 seconds. It would make
zero difference to me if it took 8 or 80.
Do you think people who work with scripting languages (or even writing
HTML) would tolerate an exasperating 12-second day between hitting Run,
and their test-run starting?
In the case of Python they tolerate hopeless performance so who knows.
You really haven't got a clue.
Says the guy who rebuilds everything from scratch each time.
On 3/24/2025 8:44 AM, Scott Lurndal wrote:
David Brown <david.brown@hesbynett.no> writes:
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
C programmers are typically not bothered about build times because a)
their build times are rarely high (Scott's projects are C++), and b),
they are willing to sacrifice high build times if it means more
efficient run times.
C++ and C aren't that far apart. I work with two codebases,
one in C++ (several million SLOC) and one in C (linux kernel).
I'd like to see Bart (try to) compile linux with his C compiler.
That would be a good test of his tool base.
David Brown <david.brown@hesbynett.no> writes:
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
C programmers are typically not bothered about build times because
a) their build times are rarely high (Scott's projects are C++), and
b), they are willing to sacrifice high build times if it means more >efficient run times.
C++ and C aren't that far apart. I work with two codebases,
one in C++ (several million SLOC) and one in C (linux kernel).
I'd like to see Bart (try to) compile linux with his C compiler.
On Mon, 24 Mar 2025 16:02:57 +0000
bart <bc@freeuk.com> wibbled:
On 24/03/2025 15:00, Muttley@DastardlyHQ.org wrote:
real 0m0.815s
user 0m0.516s
sys 0m0.252s
So, your throughput is a whopping 9.5K lines/second?
On a tired laptop with multiple files it seems pretty good to me.
Build time is 1/15th of a second, for about 30K lines (so 450Klps). But
I also want to compile this via C, to take advantage of gcc's superior
optimiser. So first I transpile to C (that's also under 70ms):
I'll paraphrase someone elses point - who fucking cares? If you need lightning
fast compilation because you're constantly rebuilding your shit code to see if
it'll even compile never mind work then that says a lot about you as a dev. The thinking/writing to compilation time ratio I imagine with most devs would probably be a minimum of 100 - 1, possibly much larger.
It's strange: in one part of the computing world, the speed of building software is a very big deal. All sorts of efforts are going on to deal
with it. Compilation speed for developers is always an issue. There is a general movement away from LLVM-based backends /because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total non-issue!
On 23/03/2025 02:34, bart wrote:
It's strange: in one part of the computing world, the speed of building
software is a very big deal. All sorts of efforts are going on to deal
with it. Compilation speed for developers is always an issue. There is a
general movement away from LLVM-based backends /because/ it is so slow.
And yet in another part (namely comp.lang.c) it appears to be a total
non-issue!
Throughout my career, far less time was spent compiling my programs than
was spent executing them.
was executed 24/7 on at least one machine, and usually hundreds, for
several months at a time, for each version delivered.
A single delivery
might involve development and testing that might require a few dozen compilations. Thanks to effective use of makefiles, most compilations
were of only a few modules at a time,
I just find compile times of even seconds annoying: [...]
I used to do that without makefiles! If you've been working on a project
for a year, then you know exactly what the dependencies are. [...]
On 24/03/2025 16:56, Muttley@DastardlyHQ.org wrote:
No, because unlike you I understand the concept of splitting into modules
and having a makefile that just rebuilds whats changed, not the entire
codebase.
I said the project used 30 modules. The generated C version is a single >module. In that form, it allows gcc to perform whole-program
No it isn't. THat example I gave you built in 0.8 seconds. It would make
zero difference to me if it took 8 or 80.
Really? It could take 80 seconds extra and you would just sit there and
take it? Boy you must really like stopping at red lights then.
In the case of Python they tolerate hopeless performance so who knows.
Perhaps they're sensible enough to use Python where that is not
relevant. However when they make a change, they want to see the results
NOW. They wouldn't even understand why there need be any delay.
Says the guy who rebuilds everything from scratch each time.
You're seriously suggesting I should use a makefile so that I can save
0.065 seconds by only compiling one module?
For that matter, why do YOU use a makefile when your full build is only
0.8 seconds?
Fast compilers and also whole-program compilers open up lots of new >possibilities. But clearly you're quite happy being stuck in the stone age.
.... EXCEPT when it comes to edit-run cycles. There you're in favour of >bunching lots of changes together, and doing one big build followed by >testing a dozen different things on that new version. (As though this
was the 1960s and you only got one batch compilation per night.)
On Mon, 24 Mar 2025 21:16:17 +0000
bart <bc@freeuk.com> wibbled:
.... EXCEPT when it comes to edit-run cycles. There you're in favour of
bunching lots of changes together, and doing one big build followed by
testing a dozen different things on that new version. (As though this
was the 1960s and you only got one batch compilation per night.)
I'm sure that made some sense to you when you wrote it. I have no idea wtf you're talking about however.
For that matter, why do YOU use a makefile when your full build is only
0.8 seconds?
Modularising code is far more than just about compilation speed which you'd know if you had anything approaching a clue.
Fast compilers and also whole-program compilers open up lots of new
possibilities. But clearly you're quite happy being stuck in the stone age.
The stone age is where they used one huge source file for a program.
On Mon, 24 Mar 2025 18:20:02 +0000
bart <bc@freeuk.com> wibbled:
Fast compilers and also whole-program compilers open up lots of new >possibilities. But clearly you're quite happy being stuck in the
stone age.
The stone age is where they used one huge source file for a program.
On Mon, 24 Mar 2025 15:44:10 GMT
scott@slp53.sl.home (Scott Lurndal) wrote:
David Brown <david.brown@hesbynett.no> writes:
On 24/03/2025 15:07, bart wrote:
On 24/03/2025 11:51, David Brown wrote:
On 23/03/2025 02:34, bart wrote:
C programmers are typically not bothered about build times because
a) their build times are rarely high (Scott's projects are C++), and
b), they are willing to sacrifice high build times if it means more
efficient run times.
C++ and C aren't that far apart. I work with two codebases,
one in C++ (several million SLOC) and one in C (linux kernel).
With computee resources you use for compilation of your simulator, compilation of Linux kernel should finish rather quickly.
At least, quickly by Muttley's standard. He said that 80 seconds are
o.k. I suppose that it would take less than that.
On 3/22/2025 4:07 AM, Peter 'Shaggy' Haywood wrote:
Groovy hepcat DFS was jivin' in comp.lang.c on Wed, 19 Mar 2025 03:42
pm. It's a cool scene! Dig it.
On 3/18/2025 11:26 PM, Keith Thompson wrote:
DFS <nospam@dfs.com> writes:
There's your problem.
https://cses.fi/problemset/text/2433
"In all problems you should read input from standard input and
write output to standard output."
ha! It usually helps to read the instructions first.
The autotester expects your program to read arguments from stdin,
not from command line arguments.
It probably passes no arguments to your program, so argv[1] is a
null
pointer. It's likely your program compiles (assuming the NBSP
characters were added during posting) and crashes at runtime,
producing no output.
I KNEW clc would come through!
Pretty easy fixes:
1 use scanf()
Normally I'd say take care with scanf(). But in this case, since
the
program is intended to be executed in an automated environment, it
should be fine.
The reason scanf() can be a bit iffy is that you can't control
what a
user will enter. If you search Google or Duck Duck Go for
"comp.lang.c faq" you can find more information on this and other
issues. (The FAQ is still out there, people..., somewhere...)
https://c-faq.com/
I still see links to that document from time to time, like on
university websites.
2 update int to long
3 handle special case of n = 1
The problem definition doesn't mention any special case. You
should, I
think, treat 1 like any other number. So the output for 1 should be
1 4 2 1
It's a 'special case' because n is already 1.
Your code passed all CSES tests but this one.
4 instead of collecting the results in a char variable, I print
them as they're calculated
Yep, that's a more usual approach.
Another suggestion I have is to use a separate function to do part
of
the work. But it's not vital.
Also, since the specification says that only positive numbers are
to
be accepted, it makes sense (to me, at least) to use an unsigned type
for n.
One more thing: using while(1){...break;} is a bit pointless. You
can
use do{...}while(1 != n) instead.
Here's my solution, for what it's worth:
#include <stdio.h>
unsigned long weird(unsigned long n)
{
printf("%lu", n);
if(n & 1)
{
/* Odd - multiply by 3 & add 1. */
n = n * 3 + 1;
}
else
{
/* Even - divide by 2. */
n /= 2;
}
return n;
}
int main(void)
{
unsigned long n;
/* Get n from stdin. */
scanf("%lu", &n);
/* Now feed it to the algorithm. */
do
{
n = weird(n);
putchar(' ');
} while(1 != n);
printf("%lu\n", n);
return 0;
}
Cool.
I tweaked my original and got it down to: --------------------------------------------------------
#include <stdio.h>
int main(void)
{
long n = 0;
scanf("%ld", &n);
while(n > 1) {
printf("%ld ",n);
n = (n % 2) ? (n * 3 + 1) : (n / 2);
}
printf("1\n");
return 0;
}
--------------------------------------------------------
I also liked the Number Spiral, Coin Piles and Palindrome Reorder
problems.
Thanks for the input!
On 24/03/2025 16:17, Muttley@DastardlyHQ.org wrote:
It's funny actually that you are in favour of the incremental builds
that makefiles help with. All about breaking things down into smaller
steps ...
... EXCEPT when it comes to edit-run cycles. There you're in favour of >bunching lots of changes together, and doing one big build followed by >testing a dozen different things on that new version. (As though this
was the 1960s and you only got one batch compilation per night.)
On 25/03/2025 08:41, Muttley@DastardlyHQ.org wrote:
On Mon, 24 Mar 2025 21:16:17 +0000
bart <bc@freeuk.com> wibbled:
.... EXCEPT when it comes to edit-run cycles. There you're in favour of
bunching lots of changes together, and doing one big build followed by
testing a dozen different things on that new version. (As though this
was the 1960s and you only got one batch compilation per night.)
I'm sure that made some sense to you when you wrote it. I have no idea wtf >> you're talking about however.
Then I have no idea WTF you're on about when you say that programmers
should spend 100 times as long thinking as they do compiling. (Try
bart <bc@freeuk.com> writes:
On 24/03/2025 16:17, Muttley@DastardlyHQ.org wrote:
It's funny actually that you are in favour of the incremental builds
that makefiles help with. All about breaking things down into smaller
steps ...
... EXCEPT when it comes to edit-run cycles. There you're in favour of
bunching lots of changes together, and doing one big build followed by
testing a dozen different things on that new version. (As though this
was the 1960s and you only got one batch compilation per night.)
EXCEPT nobody has claimed to be in favor of that. You're making shit
up again.
I'll paraphrase someone elses point - who fucking cares? If you needlightning
fast compilation because you're constantly rebuilding your shit codeto see if
it'll even compile never mind work then that says a lot about you asa dev.
The thinking/writing to compilation time ratio I imagine with mostdevs would
probably be a minimum of 100 - 1, possibly much larg
On 25/03/2025 08:40, Muttley@DastardlyHQ.org wrote:
For that matter, why do YOU use a makefile when your full build is only
0.8 seconds?
Modularising code is far more than just about compilation speed which you'd >> know if you had anything approaching a clue.
You can modularise code without also needing a makefile!
The stone age is where they used one huge source file for a program.
Maybe they also used one huge binary for a program.
You're either fucking stupid or an incredibly successful troll.
No matter how many facts you're given you ignore the ones you don't like
and twist things around to make some smart-ass comment.
On Tue, 25 Mar 2025 11:09:21 +0000
bart <bc@freeuk.com> wibbled:
On 25/03/2025 08:40, Muttley@DastardlyHQ.org wrote:
For that matter, why do YOU use a makefile when your full build is only >>>> 0.8 seconds?
Modularising code is far more than just about compilation speed which you'd >>> know if you had anything approaching a clue.
You can modularise code without also needing a makefile!
IYYM you can build modularised code without it. Sure , sometimes, so long as the modules don't have varying compilation dependencies. But then you end up rebuilding everything.
Listen sonny, in large projects in companies - ie not the toy code you work on in your bedroom - different people will have checked out seperate modules and be working on them at any one time. Thats a lot simpler than having one huge source file that then has a boatload of merge issues when a dozen people all try to check their changes back in.
So, what exactly is released to end-users?
Where is the final linking
done? If on the user's machine, will the necessary tools also be
bundled?
On 25/03/2025 14:46, Muttley@DastardlyHQ.org wrote:
On Tue, 25 Mar 2025 11:09:21 +0000
bart <bc@freeuk.com> wibbled:
On 25/03/2025 08:40, Muttley@DastardlyHQ.org wrote:
For that matter, why do YOU use a makefile when your full build is only >>>>> 0.8 seconds?
Modularising code is far more than just about compilation speed which you'd
know if you had anything approaching a clue.
You can modularise code without also needing a makefile!
IYYM you can build modularised code without it. Sure , sometimes, so long as >> the modules don't have varying compilation dependencies. But then you end up >> rebuilding everything.
And? I thought you said it didn't matter how long it took! Perhaps >compilation time does matter after all...
Listen sonny, in large projects in companies - ie not the toy code you work >> on in your bedroom - different people will have checked out seperate modules >> and be working on them at any one time. Thats a lot simpler than having one >> huge source file that then has a boatload of merge issues when a dozen people
all try to check their changes back in.
Fucking hell, you still don't get it. That single source file is >MACHINE-GENERATED. Nobody's going to be even looking inside let alone
trying to maintain it.
On Tue, 25 Mar 2025 08:40:34 -0000 (UTC)
Muttley@DastardlyHQ.org wrote:
On Mon, 24 Mar 2025 18:20:02 +0000
bart <bc@freeuk.com> wibbled:
Fast compilers and also whole-program compilers open up lots of new
possibilities. But clearly you're quite happy being stuck in the
stone age.
The stone age is where they used one huge source file for a program.
Separate compilation process and modularization/# of source files are
not directly related.
When the speed (or size, or correctness) is paramount, separate
compilation is inevitably inferior to whole-program compilation.
If people still use separate compilation, it does not happen because
it is good thing, but because compilers are too slow. Or, if we're
talking about Unix world, out of inertia.
In Windows world release builds of majority of C/C++ software is done
LTCG. Most developers do not even think about it, its a default. Even
in Linux world, projects that care about experience of their users,
like for example Firefox, use LTCG as a minimum, sometimes even going
for profile-guided whole program compilations.
Listen sonny, in large projects in companies - ie not the toy code you work on in your bedroom - different people will have checked out seperate modules and be working on them at any one time.
On Tue, 25 Mar 2025 14:58:28 +0000
bart <bc@freeuk.com> wrote:
So, what exactly is released to end-users?
I case of Firefox? An installer. After installer finished, I suppose it
ends up as directory with exe file + few DLLs.
In case of in-house software, either the same or just an exe. possibly
with few accompanying file, like default options etc...
Where is the final linking
done? If on the user's machine, will the necessary tools also be
bundled?
It seems, you are thinking about source distribution rather than normal (==binary) distribution.
You're the one extolling the virtues of a single source file, not me.
Here's an idea - instead of outputting C why don't you make it output
machine code instead. Might be more useful.
On 25/03/2025 15:14, Michael S wrote:
On Tue, 25 Mar 2025 14:58:28 +0000
bart <bc@freeuk.com> wrote:
So, what exactly is released to end-users?
I case of Firefox? An installer. After installer finished, I
suppose it ends up as directory with exe file + few DLLs.
In case of in-house software, either the same or just an exe.
possibly with few accompanying file, like default options etc...
Where is the final linking
done? If on the user's machine, will the necessary tools also be
bundled?
It seems, you are thinking about source distribution rather than
normal (==binary) distribution.
No, I want to distribute programs, but binaries are problematic, so I
have to take one step back. Instead of one convenient binary file, I
supply one convenient file in another format.
If that format is HLL code then it needs a finalising process.
I also have a private binary format, but while that may appear as
data to AV, humans might still not trust it.
On Tue, 25 Mar 2025 16:40:38 +0000
bart <bc@freeuk.com> wibbled:
On 25/03/2025 15:09, Muttley@DastardlyHQ.org wrote:
You're the one extolling the virtues of a single source file, not me.
Here's an idea - instead of outputting C why don't you make it output
machine code instead. Might be more useful.
What makes you think I don't? The C code is mainly for people who can't
or won't run Windows binaries. It also makes it incredibly easy to build >>from source (gcc prog.c).
In my case I want to apply gcc-level optimisations that my compiler
doesn't do. So it has to be C code if I want that final 25% extra speed.
Whats this? You mean your amazing zippy fast compiler can't optimise for shit?
Maybe gcc isn't so bad after all eh?
On 25/03/2025 15:09, Muttley@DastardlyHQ.org wrote:
You're the one extolling the virtues of a single source file, not me.
Here's an idea - instead of outputting C why don't you make it output
machine code instead. Might be more useful.
What makes you think I don't? The C code is mainly for people who can't
or won't run Windows binaries. It also makes it incredibly easy to build
from source (gcc prog.c).
In my case I want to apply gcc-level optimisations that my compiler
doesn't do. So it has to be C code if I want that final 25% extra speed.
Whats this? You mean your amazing zippy fast compiler can't optimise for shit?
Maybe gcc isn't so bad after all eh?
On 2025-03-26, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
Whats this? You mean your amazing zippy fast compiler can't optimise for shit?
Maybe gcc isn't so bad after all eh?
Ah, but:
- gcc doesn't produce better code than it did 25 years go, when it
was at least an order of magnitude smaller and two orders faster.
At least not for tightly written programs where the C programmer
has done optimizing at the source level, so that the compiler has
little more to think about beyond good instruction selection and
cleaning up the pessimizations it has itself introduced.
Kaz Kylheku <643-408-1753@kylheku.com> wrote:<snip>
On 2025-03-26, Muttley@DastardlyHQ.org <Muttley@DastardlyHQ.org> wrote:
Whats this? You mean your amazing zippy fast compiler can't optimise for shit?
Maybe gcc isn't so bad after all eh?
Ah, but:
- gcc doesn't produce better code than it did 25 years go, when it
was at least an order of magnitude smaller and two orders faster.
At least not for tightly written programs where the C programmer
has done optimizing at the source level, so that the compiler has
little more to think about beyond good instruction selection and
cleaning up the pessimizations it has itself introduced.
No, gcc produces better code. Both 25 years ago and now one
can find situations where gcc output could be improved by
rather simple transformations, but it is less frequent now.
In other words, typically optimization
does not lead to catastrophic increase in compile time,
both for modern and old gcc.
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
scott@slp53.sl.home (Scott Lurndal) writes:
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
How long does it take compiling with -O1?
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
scott@slp53.sl.home (Scott Lurndal) writes:
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
How long does it take compiling with -O1?
Using -O1 saves 14 seconds on the long-pole.
$ time mr -s -j96
COMPILE g.cpp
BUILD lib/lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 14m0.76s
user 13m52.28s
sys 0m20.13s
$ time md -s -j96
COMPILE g.cpp
BUILD lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 13m46.49s
user 13m42.17s
sys 0m16.66s
To be clear, we know that this is ridiculous, the generated
header file totals 1.25 million lines, including a single
function with over 200,000 SLOC. Feature creep, antique
algorithms, screwed up third-party ip-xact collateral and
tight development schedules.
Compiling with -O0 for development
testing reduces the compile time to a few seconds.
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
scott@slp53.sl.home (Scott Lurndal) writes:
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
How long does it take compiling with -O1?
Using -O1 saves 14 seconds on the long-pole.
$ time mr -s -j96
COMPILE g.cpp
BUILD lib/lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 14m0.76s
user 13m52.28s
sys 0m20.13s
$ time md -s -j96
COMPILE g.cpp
BUILD lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 13m46.49s
user 13m42.17s
sys 0m16.66s
To be clear, we know that this is ridiculous, the generated
header file totals 1.25 million lines, including a single
function with over 200,000 SLOC. Feature creep, antique
algorithms, screwed up third-party ip-xact collateral and
tight development schedules.
On 28/03/2025 16:13, Scott Lurndal wrote:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
scott@slp53.sl.home (Scott Lurndal) writes:
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
How long does it take compiling with -O1?
Using -O1 saves 14 seconds on the long-pole.
$ time mr -s -j96
COMPILE g.cpp
BUILD lib/lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 14m0.76s
user 13m52.28s
sys 0m20.13s
$ time md -s -j96
COMPILE g.cpp
BUILD lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 13m46.49s
user 13m42.17s
sys 0m16.66s
To be clear, we know that this is ridiculous, the generated
header file totals 1.25 million lines, including a single
function with over 200,000 SLOC. Feature creep, antique
algorithms, screwed up third-party ip-xact collateral and
tight development schedules.
So, 13:40 minutes for 1.25M lines? (I assume that header contains code
not just declarations.)
That would make it 1.5Kloc/second, but it also apparently over 96 cores
(or threads)? That comes to 16 lines per second per thread.
That 200K lines in one function looks suspicious
bart <bc@freeuk.com> writes:
On 28/03/2025 16:13, Scott Lurndal wrote:
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
scott@slp53.sl.home (Scott Lurndal) writes:
[...] I have one
source file that takes almost 7 minutes to compile
when using -O3 on a very-high-end xeon box. Mostly
buried in the overall compile time when using parallel
make.
The code could be restructured to compile in a few seconds;
but that would require substantial changes to the rest
of the codebase. Compiling with -O0 for development
testing reduces the compile time to a few seconds.
How long does it take compiling with -O1?
Using -O1 saves 14 seconds on the long-pole.
$ time mr -s -j96
COMPILE g.cpp
BUILD lib/lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 14m0.76s
user 13m52.28s
sys 0m20.13s
$ time md -s -j96
COMPILE g.cpp
BUILD lib_g.so
BUILDSO libsim.so.1.0
BUILD TARGET sim
real 13m46.49s
user 13m42.17s
sys 0m16.66s
To be clear, we know that this is ridiculous, the generated
header file totals 1.25 million lines, including a single
function with over 200,000 SLOC. Feature creep, antique
algorithms, screwed up third-party ip-xact collateral and
tight development schedules.
So, 13:40 minutes for 1.25M lines? (I assume that header contains code
not just declarations.)
That would make it 1.5Kloc/second, but it also apparently over 96 cores
(or threads)? That comes to 16 lines per second per thread.
The gnu compiler is not multithreaded. The single thread was
compute bound for 13 minutes and 46 seconds.
That 200K lines in one function looks suspicious
Why?
bart <bc@freeuk.com> writes:
On 28/03/2025 20:41, Scott Lurndal wrote:[...]
The gnu compiler is not multithreaded. The single thread was
compute bound for 13 minutes and 46 seconds.
So what was that -j96 about?
"-j96" is an option to GNU make, not to the compiler. It might invoke
gcc multiple times in parallel, but each invocation of gcc will still be single-threaded.
bart <bc@freeuk.com> writes:
On 28/03/2025 22:33, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 28/03/2025 20:41, Scott Lurndal wrote:[...]
"-j96" is an option to GNU make, not to the compiler. It mightThe gnu compiler is not multithreaded. The single thread was
compute bound for 13 minutes and 46 seconds.
So what was that -j96 about?
invoke
gcc multiple times in parallel, but each invocation of gcc will still be >>> single-threaded.
So, is there just once instance of gcc at work during those 13
minutes, or multiple?
In other words, would it take longer than 13:40 mins without it, or
does it help? If -j96 makes no difference, then why specify it?
I haven't done any measurements, but I don't know what's unclear.
If a single thread was compute bound for 13:46, using "-j96"
won't make that single thread run any faster, but it can enable
"make" to do other things while that single thread is running.
It's also common to use "-j" without an argument, to run as many
jobs simultaneously as possible, or "-j$(nproc)" to run as many
parallel jobs as the number of processing units available (if you
have the "nproc" command; it's part of GNU coreutils).
I can imagine "-j" causing problems if dependencies are expressed incorrectly, but I haven't run into such a problem myself.
On 28/03/2025 23:53, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 28/03/2025 22:33, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 28/03/2025 20:41, Scott Lurndal wrote:[...]
"-j96" is an option to GNU make, not to the compiler. It mightThe gnu compiler is not multithreaded. The single thread was
compute bound for 13 minutes and 46 seconds.
So what was that -j96 about?
invoke
gcc multiple times in parallel, but each invocation of gcc will
still be
single-threaded.
So, is there just once instance of gcc at work during those 13
minutes, or multiple?
In other words, would it take longer than 13:40 mins without it, or
does it help? If -j96 makes no difference, then why specify it?
I haven't done any measurements, but I don't know what's unclear.
If a single thread was compute bound for 13:46, using "-j96"
won't make that single thread run any faster, but it can enable
"make" to do other things while that single thread is running.
It's also common to use "-j" without an argument, to run as many
jobs simultaneously as possible, or "-j$(nproc)" to run as many
parallel jobs as the number of processing units available (if you
have the "nproc" command; it's part of GNU coreutils).
I can imagine "-j" causing problems if dependencies are expressed
incorrectly, but I haven't run into such a problem myself.
Are you saying that this job consists of single a C (or C++) source
file, so it is not possible to parallelise the processes necessary to
compile it? (I've not idea of gcc's capabilities there.)
That would be funny given that I've had criticisms myself for attempting
to compile monolithic C programs.
bart <bc@freeuk.com> writes:
On 28/03/2025 23:53, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
On 28/03/2025 22:33, Keith Thompson wrote:I haven't done any measurements, but I don't know what's unclear.
bart <bc@freeuk.com> writes:
On 28/03/2025 20:41, Scott Lurndal wrote:[...]
"-j96" is an option to GNU make, not to the compiler. It mightThe gnu compiler is not multithreaded. The single thread was
compute bound for 13 minutes and 46 seconds.
So what was that -j96 about?
invoke
gcc multiple times in parallel, but each invocation of gcc will still be >>>>> single-threaded.
So, is there just once instance of gcc at work during those 13
minutes, or multiple?
In other words, would it take longer than 13:40 mins without it, or
does it help? If -j96 makes no difference, then why specify it?
If a single thread was compute bound for 13:46, using "-j96"
won't make that single thread run any faster, but it can enable
"make" to do other things while that single thread is running.
It's also common to use "-j" without an argument, to run as many
jobs simultaneously as possible, or "-j$(nproc)" to run as many
parallel jobs as the number of processing units available (if you
have the "nproc" command; it's part of GNU coreutils).
I can imagine "-j" causing problems if dependencies are expressed
incorrectly, but I haven't run into such a problem myself.
Are you saying that this job consists of single a C (or C++) source
file, so it is not possible to parallelise the processes necessary to
compile it? (I've not idea of gcc's capabilities there.)
Huh??
No, I didn't say that. I was merely trying to explain how "make -j"
works, since you seemed to be confused about it. I'll assume you
understand it now. If you're curious about the source code, ask
Scott Lurndal; I don't know anything about it (and I don't know where
you got the idea that I do).
On 29/03/2025 01:32, bart wrote:
So one of Scott's compiles takes 13 minutes. "make -j" won't speed that
up. But it will mean that any other compilations can be done in
parallel. Maybe he has 600 other files that each take 30 seconds to
compile. With "make -j", the build takes the 13 minutes it has to for
the one awkward file - all the rest are compiled while that is going on.
With non-parallel "make", it would take 5 hours (if I've done my sums
correctly).
Thus "make -j" is a really good idea, even if you have a particularly >long-running task (compilation or anything else).
The bottleneck of many big builds is the link process. Traditionally,
this needs to collect together all the object files and static
libraries. In more modern systems, especially with C++, it also >de-duplicates sections. Since linking is a task that usually can't
begin until all the compilation is finished, and it is usually just one >single task, it makes sense to focus on making linking multi-threaded.
And this is what we see with modern linkers - a great deal of effort is
put into multi-threading the linking process (especially when partitions
from the link are passed back to the compiler for link-time optimisation
and code generation).
The third point from this thread, is why is gcc so slow on a particular
C file? As you have noted before, some aspects of compilation and >optimisation - particularly inter-procedural optimisation - increases >super-linearly with size, both the size of individual functions and the >number of functions. I don't know what this particular file is, but
given what I know of Scotts work and my own experience, I think this
could be a generated file for hardware simulation.
David Brown <david.brown@hesbynett.no> writes:
On 29/03/2025 01:32, bart wrote:
<snip>
So one of Scott's compiles takes 13 minutes. "make -j" won't speed that >>up. But it will mean that any other compilations can be done in
parallel. Maybe he has 600 other files that each take 30 seconds to >>compile. With "make -j", the build takes the 13 minutes it has to for
the one awkward file - all the rest are compiled while that is going on.
With non-parallel "make", it would take 5 hours (if I've done my sums >>correctly).
Thus "make -j" is a really good idea, even if you have a particularly >>long-running task (compilation or anything else).
Indeed there are several hundred source files. The one under
discussion in this thread happens to be the 'long pole' that
dominates the overall build time.
scott@slp53.sl.home (Scott Lurndal) writes:
David Brown <david.brown@hesbynett.no> writes:
On 29/03/2025 01:32, bart wrote:
<snip>
So one of Scott's compiles takes 13 minutes. "make -j" won't speed that >>> up. But it will mean that any other compilations can be done in
parallel. Maybe he has 600 other files that each take 30 seconds to
compile. With "make -j", the build takes the 13 minutes it has to for
the one awkward file - all the rest are compiled while that is going on. >>> With non-parallel "make", it would take 5 hours (if I've done my sums
correctly).
Thus "make -j" is a really good idea, even if you have a particularly
long-running task (compilation or anything else).
Indeed there are several hundred source files. The one under
discussion in this thread happens to be the 'long pole' that
dominates the overall build time.
So this discussion prompted me to manually break up that
automatically generated large function into seven smaller functions.
The compile time with -O3 dropped by a factor of almost
seven: 2 minutes 30 seconds.
Bart needs to argue about something. Anything.
It is a single source file, compiled with a single instance
of g++. That -j was provided to make is irrelevent.
Indeed there are several hundred source files. The one under
discussion in this thread happens to be the 'long pole' that
dominates the overall build time.
And this actually is a degenerate example of what happens when
one tries to include an entire program in a single source file,
something that bart seems to rather senseless continue to
advocate.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (0 / 16) |
Uptime: | 165:43:40 |
Calls: | 10,385 |
Calls today: | 2 |
Files: | 14,057 |
Messages: | 6,416,525 |