Check-in [aecd24127d]

Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:More TIP #476 updates. Add example "main.c".
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: aecd24127d9a1ddc180f8d74cd9e3de7c9d5f091ec023855821d2fdb799e8167
User & Date: jan.nijtmans 2017-10-19 12:02:40
Context
2017-10-19
12:15
No need to specify http in link (could be https as well) check-in: 440f901a49 user: jan.nijtmans tags: trunk
12:02
More TIP #476 updates. Add example "main.c". check-in: aecd24127d user: jan.nijtmans tags: trunk
08:03
Minor TIP #476 update. Fix two executable flags (which shouldn't be there) and update TIP index. check-in: 78c4a75826 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added attach/476/main.c.











































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <inttypes.h>
#include <string.h>
#include <tcl.h>
#include <stdio.h>
#include <tclTommath.h>

#ifndef TCL_Z_MODIFIER
#	define TCL_Z_MODIFIER "z"
#endif

int main() {
	Tcl_Obj *obj;

	/* Ensure proper initialization, even without TIP #414 */
	Tcl_CreateInterp();

	printf("LL modifier: \"%s\"    Z modifier: \"%s\"\n", TCL_LL_MODIFIER, TCL_Z_MODIFIER);
	/* Hex string with prefix */
	printf("%#x\n", 15);
	obj = Tcl_ObjPrintf("%#x", 15);
	printf("%s\n", Tcl_GetString(obj));

	/* 0 Hex string with prefix */
	printf("%#x\n", 0);
	obj = Tcl_ObjPrintf("%#x", 0);
	printf("%s\n", Tcl_GetString(obj));

	/* Hex string with prefix, uppercase */
	printf("%#X\n", 15);
	obj = Tcl_ObjPrintf("%#X", 15);
	printf("%s\n", Tcl_GetString(obj));

	/* Hex float with prefix */
	printf("%a\n", 1.75);
	obj = Tcl_ObjPrintf("%a", 1.75);
	printf("%s\n", Tcl_GetString(obj));

	/* Hex float with prefix, uppercase */
	printf("%A\n", 1.75);
	obj = Tcl_ObjPrintf("%A", 1.75);
	printf("%s\n", Tcl_GetString(obj));

	/* int32_t */
	int32_t i32 = 45;
	printf("%" PRId32 "\n", i32);
	obj = Tcl_ObjPrintf("%" PRId32, i32);
	printf("%s\n", Tcl_GetString(obj));

	/* int64_t */
	int64_t i64 = 46;
	printf("%" PRId64 "\n", i64);
	obj = Tcl_ObjPrintf("%" PRId64, i64);
	printf("%s\n", Tcl_GetString(obj));

	/* (unsigned) Tcl_WideInt / long long */
	Tcl_WideUInt w = 47;
	unsigned long long ll = (unsigned long long) w;
	printf("%" TCL_LL_MODIFIER "u\n", w);
	obj = Tcl_ObjPrintf("%" TCL_LL_MODIFIER "u", w);
	printf("%s\n", Tcl_GetString(obj));
	printf("%" TCL_LL_MODIFIER "u\n", ll);
	obj = Tcl_ObjPrintf("%" TCL_LL_MODIFIER "u", ll);
	printf("%s\n", Tcl_GetString(obj));
	printf("%llu\n", w);
	obj = Tcl_ObjPrintf("%llu", w);
	printf("%s\n", Tcl_GetString(obj));
	printf("%llu\n", ll);
	obj = Tcl_ObjPrintf("%llu", ll);
	printf("%s\n", Tcl_GetString(obj));

	/* size_t */
	size_t s = 48;
	printf("%" TCL_Z_MODIFIER "u\n", s);
	obj = Tcl_ObjPrintf("%" TCL_Z_MODIFIER "u", s);
	printf("%s\n", Tcl_GetString(obj));

	/* intmax_t */
	intmax_t m = 49;
	printf("%jd\n", m);
	obj = Tcl_ObjPrintf("%jd", m);
	printf("%s\n", Tcl_GetString(obj));

	/* ptrdiff_t */
	ptrdiff_t p = 50;
	printf("%td\n", p);
	obj = Tcl_ObjPrintf("%td", p);
	printf("%s\n", Tcl_GetString(obj));

	/* long double */
	long double ld = 51.75;
	printf("%Lg\n", ld);
	obj = Tcl_ObjPrintf("%Lg", ld);
	printf("%s\n", Tcl_GetString(obj));

	/* mp_int */
	mp_int mp;
	mp_init_size(&mp, 0);
	mp_set_int(&mp, 52);
	obj = Tcl_ObjPrintf("%Ld", &mp);
	printf("%s\n", Tcl_GetString(obj));
}

Changes to tip/476.md.

21
22
23
24
25
26
27


28



29






















30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47












48
49
50
51











52


53
54



55
56
57
58
59
60




61
62
63
64
65
66
67
68
69
it produces the "0o" prefix in stead of "o". This is a small step in the
direction of phasing out octal (TIP #114). Finally this TIP modifiers
the %#d modifier, such that it only produces a "0d" prefix if that
is needed for correct interpretation of the number when parsing it.

# Rationale



TODO



























# Specification

This TIP proposes serveral things:

   *   Whenever possible, typedef Tcl_WideInt to be equal to long long, even
       on platforms where long has the same size as long long.

   *   Document the already existing TCL\_LL\_MODIFIER macro to be equivalent
       to "ll" whenever possible. This is used already to format/scan variables
       of type Tcl\_WideInt/Tcl\_WideUInt, but now it can be used also for
       variables of type long long or \_\_int64 (Windows). The obligation to
       use Tcl\_WideInt/Tcl\_WideUInt in extensions (enforced by compiler
       warnings) is now gone: Most compilers understand "long long" now.

   *   Add a new TCL\_Z\_MODIFIER macro to be equivalent to "z" whenever possible.
       This can be used to format/scan variables of type size\_t or ptrdiff\_t.
       If your compiler is ISO C99-compatible, you can use "z" resp "t" instead.













   *   No longer let the "%llu" format generate an error if the formatted number
       is positive.












   *   Adapt the %#o modifier (TODO: explain)



   *   Adapt the %#d modifier (TODO: explain)




# Considerations regarding the incompatibility

This change is fully upwards compatible. As long as Tcl extensions use the
Tcl\_WideInt/Tcl\_WideUInt data types (in stead of long long or \_\_int64),
everything works as before.





# Reference Implementation

<https://core.tcl.tk/tcl/timeline?r=z_modifier>

# Copyright

This document is placed in public domain.








>
>
|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|




>
>
>
>
>
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>
>
>
>
|
>
>

|
>
>
>



|


>
>
>
>








<
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

it produces the "0o" prefix in stead of "o". This is a small step in the
direction of phasing out octal (TIP #114). Finally this TIP modifiers
the %#d modifier, such that it only produces a "0d" prefix if that
is needed for correct interpretation of the number when parsing it.

# Rationale

For an example program containing all situations mentioned here,
see [main.c](http:../attach/476/main.c)

First of all, when compiling the example program on 64-bit linux
(with -DTCL\_WIDE\_INT\_IS\_LONG=1), gcc outputs 5 warnings, 4 of them
are unnecessary:

<pre>
main.c: In function 'main':
main.c:61:9: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'long long unsigned int' [-Wformat=]
  printf("%" TCL_LL_MODIFIER "u\n", ll);
         ^~~
main.c:62:22: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'long long unsigned int' [-Wformat=]
  obj = Tcl_ObjPrintf("%" TCL_LL_MODIFIER "u", ll);
                      ^~~
main.c:64:13: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'Tcl_WideUInt {aka long unsigned int}' [-Wformat=]
  printf("%llu\n", w);
             ^
main.c:65:26: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'Tcl_WideUInt {aka long unsigned int}' [-Wformat=]
  obj = Tcl_ObjPrintf("%llu", w);
                          ^
main.c:99:25: warning: format '%Ld' expects argument of type 'long long int', but argument 2 has type 'mp_int * {aka struct mp_int *}' [-Wformat=]
  obj = Tcl_ObjPrintf("%Ld", &mp);
                         ^~~
</pre>

The last warning arises because the C printf formatter doesn't handle mp_int types, this warning can be safely ignored.

The other 4 warnings arise because Tcl_WideInt is defined as being the same as long on this sytem. Making it the same as long long fully eliminates those warnings.

# Specification

This TIP proposes serveral things:

   *   Whenever possible, typedef Tcl_WideInt to be equal to long long, even
       on platforms where long has the same size as long long.

   *   Document the already existing TCL\_LL\_MODIFIER macro to be equivalent
       to "ll" whenever possible. This is used already to format/scan variables
       of type Tcl\_WideInt/Tcl\_WideUInt, but now it can be used also for
       variables of type long long or \_\_int64 (Windows). The obligation to
       use Tcl\_WideInt/Tcl\_WideUInt in extensions (enforced by compiler
       warnings) is now gone: "long long" can always be used in stead.

   *   Add a new TCL\_Z\_MODIFIER macro to be equivalent to "z" whenever possible.
       This can be used to format/scan variables of type size\_t or ptrdiff\_t.
       If your compiler is ISO C99-compatible, you can use "z" resp "t" instead.

   *   Add the "a" and "A" type fields, for formatting floats in hex. Conforming
       to ISO C99, except that the "p" in the output is always lowercase.

   *   Allow macro's from \<inttypes.h\>, such as PRId32 and PRId64, to be used in
       Tcl\_ObjPrintf(). All that is needed in Tcl is making the format characters
       mean _exactly_ the same as they do in C. See: <https://en.wikipedia.org/wiki/Printf_format_string>
       Missing were the "t", "z" and "j" modifier (unknown to MSVC as well), and "q"
       for BSD platforms. For windows, "I", "I32" and "I64" are needed. With those
       additions, the Tcl handling of the \<inttypes.h\> macros is fully ISO C99
       compatible, even on platforms which don't have an ISO C99
       conformant printf.

   *   No longer let the "%llu" format generate an error if the formatted number
       is positive.

   *   Add a new "L" length modifier. When used in combination with "f" or "g",
       it allows long doubles to be formatted. Since Tcl doesn't handle long doubles
       internally, it is converted to a normal double internally first.
       For integers, "L" indicates that the value to be formatted is of type mp_int,
       the function expect a pointer to it as argument. Since standard C printf
       format handles don't handle mp\_int types, this will result in a gcc warning,
       which can be safely ignored.

   *   Adapt the %#x and %#X modifier, such that the "x" in the output is always lowercase.
       If the formatted number is 0, no "0x" prefix is produced.

   *   Adapt the %#o modifier to use "0o" as octal prefix in stead of "0".
       This prefix is only produced when the formatted number is not 0,
       i.e. when there is possible confusion with a decimal number.

   *   Adapt the %#d modifier. The prefix "0d" is only produced when there is
       a width field and the formatted number is not 0, i.e. when there is
       possible confusion with an octal number. Since in Tcl 9.0 octal numbers
       with "0" prefix will be gone, "#" will not produce the decimal prefix any more.

# Considerations regarding the incompatibility

This change is almost fully upwards compatible. As long as Tcl extensions use the
Tcl\_WideInt/Tcl\_WideUInt data types (in stead of long long or \_\_int64),
everything works as before.

In some situations, "format" doesn't produce the exact same output as Tcl 8.6
any more, but only rarely used corner cases are affected. As the "main.c"
example shows, the result is more similar to ISO C99 than before.

# Reference Implementation

<https://core.tcl.tk/tcl/timeline?r=z_modifier>

# Copyright

This document is placed in public domain.