简体   繁体   中英

Does gcc(windows + MinGW) defines SCNd8, SCNu8 in inttypes.h?

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    int8_t int8;
    int16_t int16;
    int32_t int32;
    int64_t int64;

    uint8_t uint8;
    uint16_t uint16;
    uint32_t uint32;
    uint64_t uint64;

    scanf("%"SCNd8"%"SCNd16"%"SCNd32"%"SCNd64"%"SCNu8"%"SCNu16"%"SCNu32"%"SCNu64, 
            &int8, &int16, &int32, &int64, &uint8, &uint16, &uint32, &uint64);

    printf("%"PRId8"\n%"PRId16"\n%"PRId32"\n%"PRId64"\n%"PRIu8"\n%"PRIu16"\n%"PRIu32"\n%"PRIu64"\n",
            int8, int16, int32, int64, uint8, uint16, uint32, uint64);

    return 0;
}

I can't compile this code using latest gcc + MinGW + Netbeans + Windows. Netbeans says "unable to resolve identifier SCNd8 and SCNu8". I can't find any reference for SCNd8 and SCNu8 on gcc man page although http://linux.die.net/include/inttypes.h defines them. I don't receive syntax error for using PRId8 or PRIu8.

MinGW inttypes.h (lacks SCNd8 and SCNu8 ) (sample code)

#define PRIXFAST64 "I64X"

#define PRIXMAX "I64X"
#define PRIXPTR "X"

/*
 *   fscanf macros for signed int types
 *   NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t
 *   (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have
 *   no length identifiers
 */

#define SCNd16 "hd"
#define SCNd32 "d"
#define SCNd64 "I64d"

#define SCNdLEAST16 "hd"
#define SCNdLEAST32 "d"
#define SCNdLEAST64 "I64d"

#define SCNdFAST16 "hd"    

Interesting - I have MinGW with GCC Version 4.5.1 installed.

The format specifier macros in inttypes.h work for the most part, except for the the ones for inputting 8-bit ints ( SCNd8 and SCNu8 ). Those macros are defined in inttypes.h , but trying to use them doesn't work so well. With the following code:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    int8_t int8 = 0;
    uint8_t uint8 = 0;

    scanf("%"SCNd8, &int8);
    scanf("%"SCNu8, &uint8);

    return 0;
}

I get the following warnings:

C:\temp\test.c: In function 'main':
C:\temp\test.c:9:5: warning: unknown conversion type character 'h' in format
C:\temp\test.c:9:5: warning: too many arguments for format
C:\temp\test.c:10:5: warning: unknown conversion type character 'h' in format
C:\temp\test.c:10:5: warning: too many arguments for format

So it seems that GCC 4.5.1 and/or glibc don't support the "%hhd" and "%hhu" C99 format specifiers. If I run this program under a debugger, more than just the byte variables do end up being modified by the scanf() calls.

Just for reference, I'm using the following command to compile:

 "C:\MinGW\bin\gcc" -std=c99 -Wall -g  -Ic:\MinGW\include -D_WIN32_WINNT=0x0500 "C:\temp\test.c"  -lkernel32 -luser32 -lgdi32 -ladvapi32 -lshlwapi -loleaut32 -o "test".exe

Note that the various character-sized int input formats (that use "hh") in inttypes.h only get compiled in if the C99 standard is specified - they're protected by:

#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L

The other format specifiers are compiled in even for C90 compiles.

So you won't get the "hh" formats unless you use the -std=c99 or -std=gnu99 options (but remember that they don't seem to work anyway).


Update:

Of course! The reason the "hhd" and "hhu' specifiers aren't supported is because the MinGW runtime uses the scanf() from Microsoft's msvcrt.dll which doesn't know anything about the new stuff in C99's input formats. If you want to use these input formats, you'll need to use some other scanf() implementation.

As mentioned in MinGW's inttypes.h :

MS runtime scanf appears to treat "hh" as "h"

You could add the following after #include <inttypes.h> :

#ifndef SCNd8
  #define SCNd8 "hhd"
#endif
#ifndef SCNu8
  #define SCNu8 "hhu"
#endif

Which should be appropriate for most platforms.

Clarification: Where "most platforms" refers to platforms with a C99-compliant fscanf / scanf that can handle the hh prefix for char , not just the h prefix for short .

If you are using MinGW-w64, then according to the MinGW-w64 FAQ , use the following define before includes

#define __USE_MINGW_ANSI_STDIO 1

That means to use MinGW-w64's own stdio.h implementation, instead of deferring to Microsoft's one which does not support SCNu8 . This is a good idea anyway as the Microsoft implementation has various other major bugs.

There are two entries in the FAQ concerning the problem, here's the link to the other one .


I tested this using using gcc (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 5.1.0 with the following code

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
  uint_fast8_t i = 0;
  scanf("%" SCNuFAST8 "\n", &i);
  printf("%" PRIuFAST8 "\n", i);
  return EXIT_SUCCESS;
}

Without the __USE_MINGW_ANSI_STDIO , I got

a.c: In function 'main':
a.c:7:9: error: unknown conversion type character 'h' in format [-Werror=format=]
   scanf("%" SCNuFAST8 "\n", &i);
         ^
a.c:7:9: error: too many arguments for format [-Werror=format-extra-args]

I'm compiling my code like this

>gcc -std=c11 -Wall -Werror a.c

The SCN macros are in the C99 standard, so something is going wrong. Perhaps you'd have to compile with -std=c99 .

Well ... apparently the combination "latest gcc + MinGW + Netbeans + Windows" does not provide a compliant C99 compiler.

The standard specifically documents those identifiers as being defined in the header <inttypes.h>

7.8 Format conversion of integer types <inttypes.h>
[...]
7.8.1 [...] [#4] The fscanf macros for signed integers are:

 SCNdN SCNdLEASTN SCNdFASTN SCNdMAX SCNdPTR SCNiN SCNiLEASTN SCNiFASTN SCNiMAX SCNiPTR [#5] The fscanf macros for unsigned integers are: SCNoN SCNoLEASTN SCNoFASTN SCNoMAX SCNoPTR SCNuN SCNuLEASTN SCNuFASTN SCNuMAX SCNuPTR SCNxN SCNxLEASTN SCNxFASTN SCNxMAX SCNxPTR

我看到这是在 MinGW-w64 版本 7 的inttypes.h中定义的。您可以从以下位置获得带有此 MinGW-w64 版本的 GCC: http ://winlibs.com

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM