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

我的梦境 提交于 2020-01-13 10:17:12

问题


#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"    

回答1:


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.




回答2:


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"




回答3:


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




回答4:


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



回答5:


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


来源:https://stackoverflow.com/questions/4101335/does-gccwindows-mingw-defines-scnd8-scnu8-in-inttypes-h

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!