printf格式基于数据类型

时间:2017-11-16 13:29:57

标签: c++ types printf

我有一个带有简单打印功能的模板缓冲类。

template <typename valueType, typename sumType, int N>
class IM_buffer
{
public:
    IM_buffer()
        : bufferValues(), numValues(-1), currentSum() { }

    void record(valueType sample)
    {
        // Set buffer index to be recorded
        numValues++;

        // Get memory location for oldest element in buffer
        valueType& oldest = bufferValues[modIdx(numValues)];

        // Add the input value to the current sum and take away the value being replaced
        currentSum += sample - oldest;

        // And now do the actual replacement in the same memory location
        oldest = sample;
    }

    valueType   getCurrent()            { return bufferValues[modIdx(numValues)];           }
    valueType   getNthPrev(int Nprev)   { return bufferValues[modIdx(numValues-Nprev)];     }
    sumType     getCurrentSum()         { return currentSum;                                }
    double      getAvg()                { return (double) currentSum / MIN(numValues+1, N); }
    int         getNumValues()          { return numValues+1;                               }
    int         getBufferSize()         { return N;                                         }

    void printBuff()
    {
        for (int ii=0; ii<N; ii++)
        {
            // if it's an integer type I need:
            printf("bufferValues[%2d]=%4d\n",ii,bufferValues[ii]);
            // but if it's a floating point type I need:
            printf("bufferValues[%2d]=%8g\n",ii,bufferValues[ii]);
        }
    }

    void clear()
    {
        for (int ii=0; ii<N; ii++)
            bufferValues[ii] = (valueType) 0.0;
        numValues = 0;
        currentSum = (sumType) 0.0;
    }

private:
    valueType bufferValues[N];
    int numValues;
    sumType currentSum;

    int modIdx(int a) { return (a % N + N) % N; }
};

但是,printf的格式字符串应该取决于数据类型是什么(例如int,vs。float,vs double)。我看过像this这样的讨论,但我并不想打印出数据类型,我只需要根据数据类型更改printf格式字符串。任何人都可以指出我正确的方向,如何实现一些条件逻辑来选择正确的printf

3 个答案:

答案 0 :(得分:1)

正如评论中提到的其他人一样,您应该使用对所有内置类型都有重载的std::cout。但是,如果你真的坚持使用printf,你可以尝试以下黑客攻击:

#include <typeinfo>  // for typeid

std::string printfCmd("I wish to print this: ");
// int myVar = 69;  // uncomment to change var type to int
char myVar = 'd';
if (typeid(int) == typeid(myVar)) {
    printfCmd += "%d";
} else if (typeid(char) == typeid(myVar)) {
    printfCmd += "%c";
} else {
    // some warning/error
}

printf(printfCmd.c_str(), myVar);

这不是一个好的解决方案,只有在你真的需要时才使用它。

答案 1 :(得分:0)

如果您不想使用C ++重载的插入运算符,您可以编写自己的重载函数:

void print(int i) {
    printf("%4d",i);
}

void print(double d) {
    printf("%8g",d);
}

现在,您可以在需要时通过print功能致电printBuff

printf("bufferValues["%2d] =",ii);
print(bufferValues[ii]);
printf("\n");

答案 2 :(得分:0)

根据您的情况,另一种可能比其他解决方案更好也可能不会更好,它是使用模板在编译时根据类型对格式说明符进行模板化。

TL;DR 示例程序(链接如下):

无论如何:

template <typename T> static const char *outFormat = ""; // pick a default.
template <> const char *outFormat<float> = "%8.4f";
template <> const char *outFormat<double> = "%8.4lf";
template <> const char *outFormat<long double> = "%8.4Lf";
template <> const char *outFormat<char> = "%c";

并像这样使用它们,例如:

typedef float some_api_type; // some external libraries unknown type

void printAPIValue (some_api_type value) {
    printf(outFormat<some_api_type>, value);
    printf("\n");
}

// or, for example, printing an stl container...
template <typename Container> void printValues (const Container &c) {
    using value_type = typename Container::value_type;
    printf("[ ");
    for (auto i = c.cbegin(); i != c.cend(); ++ i) {
        printf(outFormat<value_type>, *i);
        printf(" ");
    }
    printf("]\n");
}

所以,例如this program

some_api_type value = 4;
std::vector<float> floats = { 1.0f, 1.1f, -2.345f };
std::vector<char> chars = { 'h', 'e', 'l', 'l', 'o' };

printAPIValue(value);
printValues(floats);
printValues(chars);

会产生这样的输出:

  4.0000
[   1.0000   1.1000  -2.3450 ]
[ h e l l o ]

上述内容有多种形式,因此您必须做一些适合您情况的事情。例如:

  • 为方便起见,我指定了 % 和字段宽度/精度。您可以删除所有这些并根据需要构建它,在这种情况下,使用 std::string 可能会为您节省一些输入时间。 This program

      template <typename T> static string outFormat;
      template <> const string outFormat<float> = "f";
      template <> const string outFormat<int> = "d";
    
      // graceful handling of unsupported types omitted.
      template <typename Container> void printValues (const Container &c) {
          using value_type = typename Container::value_type;
          int index = 0;
          printf("list with format %s:\n", outFormat<value_type>.c_str());
          for (auto i = c.cbegin(); i != c.cend(); ++ i, ++ index) {
              string format = "item[%d] = %10" + outFormat<value_type> + "\n";
              printf(format.c_str(), index, *i);
          }
      }
    
      int main () {
          std::vector<float> floats = { 1.0f, 1.1f, -2.345f };
          std::vector<int> ints = { -1, 1, -2, 9 };
          printValues(floats);
          printValues(ints);
      }
    

    输出:

      list with format f:
      item[0] =   1.000000
      item[1] =   1.100000
      item[2] =  -2.345000
      list with format d:
      item[0] =         -1
      item[1] =          1
      item[2] =         -2
      item[3] =          9
    
  • 您还可以将 cinttypes(C 的 inttypes.h)用于一些与平台无关的内容,例如this program

      #include <cstdio>
      #include <cinttypes> // types and PRI* sized format specifiers
    
      template <typename T> static const char *hexFormat = "<unsupported type>";
      template <> const char *hexFormat<uint8_t> = "0x%02" PRIx8;
      template <> const char *hexFormat<uint16_t> = "0x%04" PRIx16;
      template <> const char *hexFormat<uint32_t> = "0x%08" PRIx32;
      template <> const char *hexFormat<uint64_t> = "0x%016" PRIx64;
    
      template <typename UIntValue> void printHex (UIntValue value) {
          printf(hexFormat<UIntValue>, value);
          printf("\n");
      }
    
      int main () {
          printHex((size_t)0xABCD1234);
          printHex(9U);
          printHex(9UL);
          printHex((unsigned char)'!');
          printHex(9.0);
      }
    

    在 64 位平台上,可能会输出:

      0x00000000abcd1234
      0x00000009
      0x0000000000000009
      0x21
      <unsupported type>
    
  • 您有多种选择来强制使用支持的类型,我不打算列出它们,发挥您的想象力。但;由于您使用的是模板,因此您可以根据需要进行一些编译时检查。例如,this program,使用 static_assert:

      #include <cstdio>
    
      template <typename T> static constexpr const char *format = nullptr;
      template <> constexpr const char * format<short> = "%hd\n";
      template <> constexpr const char * format<int> = "%d\n";
      template <> constexpr const char * format<long> = "%ld\n";
    
      template <typename Value> void print (Value value) {
          static_assert(format<Value> != nullptr, "Unsupported type.");
          printf(format<Value>, value);
      }
    
      int main () {
          print<short>(1);
          print<int>(1);
          print<float>(1);  // <-- compilation will fail here
          print<long>(1);
      }
    

    将无法编译该 print<float> 行:

      error: static assertion failed: Unsupported type.
    

    这可以帮助您发现错误。


关于这一切,可能还有很多话要说,但我厌倦了打字,需要回去工作。希望这对某人有帮助。