patterncMinor
Formatted print without the need to specify type matching specifiers using _Generic
Viewed 0 times
withouttheneedtypeformatted_genericprintspecifiersusingspecify
Problem
This code allows printing in C with a style similar to C++
No more mis-matched specifiers!
Requested review goals:
-
Design concept: Ways to improve?
-
Implementation: What weakness & strengths exist?
4 parts:
-
-
Output
-
-
main.c
Output
GPrint.h
```
/*
* GPrint.c
*
* Created on: Dec 23, 2015
* Author: chux
*/
#ifndef GPRINT
#define GPRINT 1
#include
#include
#include
typedef enum {
GP_none,
GP__Bool,
GP_char,
GP_s
ostream. By using _Generic() (see GP()) to form a string specifier, the compiler handles the selection of printf() specifiers.No more mis-matched specifiers!
Requested review goals:
-
Design concept: Ways to improve?
-
Implementation: What weakness & strengths exist?
4 parts:
-
main.c to show a sample use. GPrintf() must end in GP_eol or NULL-
Output
-
GPrint.h Key macro GP()-
GPrint.c void GPrintf(const char *format, ...) main.c
#include "GPrint.h"
#include
int main(void) {
double q = 1000000.0 / 7;
int i = 42;
GPrintf("42 --> base 10:", GP(i),
GP_setbase(2), " 2:", GP(i),
GP_setbase(36), " 36:", GP(i), GP_eol);
GPrintf("million/7 = ", GP(q), GP_eol);
GPrintf("million/7 = ", GP_setprecision(3), GP(q), GP_eol);
GPrintf("million/7 = ", GP_fixed, GP(q), GP_eol);
GPrintf("million/7 = ", GP_fixed, GP_setprecision(3), GP(q), GP_eol);
for (int y = 1; y < 9; y++) {
int x = y * y;
GPrintf(GP_setw(2), GP(y), ",", GP(x), ":", NULL);
GPrintf(GP_repeat(x), GP((char)'*'), GP_eol);
}
GPrintf(GP_setw(5), GP(" "), ":", NULL);
for (int x = 0; x < 70; x += 5)
GPrintf("----+", NULL);
GPrintf(GP_eol);
return 0;
}Output
42 --> base 10:42 2:101010 36:16
million/7 = 1.4285714285714287e+05
million/7 = 1.429e+05
million/7 = 142857.1428571428696159
million/7 = 142857.143
1, 1:*
2, 4:****
3, 9:*********
4,16:****************
5,25:*************************
6,36:************************************
7,49:*************************************************
8,64:****************************************************************
:----+----+----+----+----+----+----+----+----+----+----+----+----+----+GPrint.h
```
/*
* GPrint.c
*
* Created on: Dec 23, 2015
* Author: chux
*/
#ifndef GPRINT
#define GPRINT 1
#include
#include
#include
typedef enum {
GP_none,
GP__Bool,
GP_char,
GP_s
Solution
Technicality
Pedantically speaking, the
Simple enough to fix: wrap all the arguments, including the first one and any string literal with
You could enforce that with an assertion in
I can't think of real-world circumstances on ordinary compilers/environments where this particular usage would be problematic though.
Pedantically speaking, the
GP_get_type function has undefined behavior if the pointer it gets isn't a pointer into (or one past the end of) GP_format (see §6.5.8/5 Relational operators).Simple enough to fix: wrap all the arguments, including the first one and any string literal with
GP.You could enforce that with an assertion in
GP_get_type (instead of the if, get rid of the default), but... you can't escape undefined behavior in that assertion :-)I can't think of real-world circumstances on ordinary compilers/environments where this particular usage would be problematic though.
Context
StackExchange Code Review Q#115143, answer score: 7
Revisions (0)
No revisions yet.