0

Do we use lu and unsigned long cast like in:

printf("%lu\n", (unsigned long)BUFSIZ); /* 512 */

and hope for the best? or there is another way?

And this is not a duplicate of: How can one print a size_t variable portably using the printf family? simply because I don't know what BUFSIZ type is.

Bite Bytes
  • 1,455
  • 8
  • 24

3 Answers3

4

I assume BUFSIZ is always a value fitting into size_t and there are no other guarantees.

In that case: Yes, this is the most correct way to do it if you're limited to . The lack of a format length modifier suitable for size_t is one of the many shortcomings in this very old standard. In practice, if you're on a 64bit system with LLP64 data model (this is, Win64), size_t is indeed larger than long and this code can break for large sizes. Thanks EOF for the hint. Still in practice: It probably should be defined reasonably and an I/O-Buffer sized 4G or larger doesn't sound reasonable, so it really is unlikely to run into problems with the "casting to unsigned long" approach.

Additional note: There might be a valid reason to use this construct even with a compiler in or mode, and that is portability to the windows platform. Microsoft's msvcrt (the C runtime and standard library) doesn't support the z length modifier.

  • Pretty sure on 64-bit windows `sizeof(size_t) > sizeof(unsigned long)`. – EOF May 31 '17 at 19:22
  • Oh, I guess you're right. And then you're doomed because `ll` doesn't work either ... –  May 31 '17 at 19:24
  • The question specifies that `BUFSIZ` is used as a macro constant, so it may not be declared with type `size_t`. If the programmer needing to print this constant also has the freedom to redefine it, your solution seems reasonable. But if it exists in some legacy code or something, and it's not reasonable to change it (perhaps it's used in all kinds of strange scopes), then this would not be relevant. – ely May 31 '17 at 19:24
  • Microsoft's compiler doesn't let you specify the standard, so it's not an option anyway. – Bite Bytes May 31 '17 at 19:25
  • Felix MSVC recent versions do support `%zu` format spec. – Weather Vane May 31 '17 at 19:44
  • @WeatherVane not last time I checked, a few days ago, on windows 10. –  May 31 '17 at 19:45
  • That is a windows version, not a compiler version? I am on Windows 7 with MSVC 2015, having binned windows 10. – Weather Vane May 31 '17 at 19:46
1

According to the C Standard (7.21 Input/output )

SETBUF

which expands to an integer constant expression that is the size of the buffer used by the setbuf function;

It is unspecified what is the type of the constant.

On the other hand the standard function setvbuf can be used to specify a user-supplied buffer or the buffer allocated by the function. It has the following declaration

int setvbuf(FILE * restrict stream,
char * restrict buf,
int mode, size_t size);

where the parameter size of the type size_t specifies the size of the buffer.

As the size can not be a negative number then you may output its value as having the type size_t.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Whether the size can be negative is irrelevant. Also, the type of the parameter to `setvbuf()` is not particularly relevant either, since an argument of any other integer type would automatically be converted to `size_t`, provided the prototype for `setvbuf()` is available, so `BUFSIZE` could be another integer type. In that case passing it to `printf()` is problematic because `printf()` is varargs. – EOF May 31 '17 at 19:30
  • @EOF You contradict yourself. If you say that whether the size is negative is irrelevant then what will be with the size when it will be converted to size_t? So it is your comment that is irrelevant and wrong. – Vlad from Moscow May 31 '17 at 19:32
  • No. You simply do not understand the problem at hand. If you wanted to understand it, I'd recommend reading in the C11 draft standard n1570 about `6.5.2.2 Function calls`, particularly the intricacies of argument conversion with regard to varargs-functions. – EOF May 31 '17 at 19:35
  • @EOF Think about how negative value will be converted to size_t. And think about what the type of the parameter size of the function setvbuf that specifies the size of the buffer. And think also about what is the type of the value returned for example by the sizeof operator for a character array that is supplied to the function as an argument. So your comment does not make sense. It is irrelevant for my answer. – Vlad from Moscow May 31 '17 at 19:37
  • As I said, negative values are irrelevant. It's really simple: 1. Have `BUFSIZ` be of type `T1`. 2. Call `setvbuf()` with `BUFSIZ` as `size`. Here, since `setvbuf()` has a prototype, `T1` will be converted to `size_t` automatically. 3. Call `printf()` with `BUFSIZ`. Here, since `printf()` is varags, `T1` **will not be converted**, so whatever random insane unspecified type `T1` was, you would need to have the right `%`-conversion specifier for. You don't. – EOF May 31 '17 at 19:41
  • @VladfromMoscow did you mean `BUFSIZ` in your first code block? –  May 31 '17 at 19:43
  • @EOF It is very important that size can not be negative, It means that there is no great sense to use a signed integer type to output the size. If the size is negative then the automatic conversion yields a wrong value. So all your comments do not make sense. – Vlad from Moscow May 31 '17 at 19:43
  • @VladfromMoscow There are more distinct, **incompatible** integer types than just `signed` and `unsigned`. – EOF May 31 '17 at 19:45
  • @FelixPalmen I provided the description of the BUFSIZ from the standard. And then I provided the standard function that can be used to set the size of the buffer. – Vlad from Moscow May 31 '17 at 19:45
  • @EOF I already wrote that all your comments do not make sense. – Vlad from Moscow May 31 '17 at 19:46
  • @VladfromMoscow Writing that does not make it true. – EOF May 31 '17 at 19:47
1

Well, it is easy to find proof that BUFSIZ is certainly not always of type size_t. Consider the following fragment test.c:

#include <stdio.h>
BUFSIZ

Compile it on Linux and:

% gcc -E test.c|tail -n 2
# 2 "test.c" 2
8192

Thus, it certainly isn't of type size_t always. The constant migth be of type int but it might also not be an int, so the safest should be to assume that it can be cast as size_t since the argument to setvbuf is also of type size_t.

Then, use the advice from How can one print a size_t variable portably using the printf family?