代码之家  ›  专栏  ›  技术社区  ›  k06a

结构的Printf?(C/C++,VC2008)

  •  5
  • k06a  · 技术社区  · 14 年前

    只需在VC2008中构建并运行此程序:

    struct A
    {
       int a;
       int b;
       int c;
    };
    A a = { 10, 20, 30 };
    printf("%d %d %d\n", a);
    

    正常吗?

    10 20 30
    

    我想选演员!但它不起作用:

    struct A
    {
       int a;
       int b;
       int c;
       operator int()
       {
          return a + b + c;
       }
    };
    A a = { 10, 20, 30 };
    printf("%d\n", a);
    

    10
    

    这里是: https://code.google.com/p/boolib/source/browse/boolib/crypt/ShakedValue.h 它应该隐藏在内存中,任何黑客程序(ArtMoney)都找不到价值。

    还有一个诀窍: 打印结构/类的私有成员

    8 回复  |  直到 14 年前
        1
  •  10
  •   Blindy    14 年前

    如果你想选演员,那就选:

    struct A
    {
       int a;
       int b;
       int c;
       operator int()
       {
          return a + b + c;
       }
    };
    A a = { 10, 20, 30 };
    printf("%d\n", (int)a);
    

    60
    
        2
  •  5
  •   Fred Foo    14 年前

    它是未定义的行为,因此在某种意义上,对于这个函数调用,每个可能的行为都可以称为“正常”。不过,这是可以解释的。

    printf 在格式字符串后接受可变数目的参数。这些文件的打包方式由实现决定。VisualC++将内存中的参数打包成与您的成员相同的方式。 struct A ,所以每次它打电话 va_arg a .

    打印 声明为 int printf(char const *, ...) ... 是非类型化参数的范围。

        3
  •  5
  •   Jens Gustedt    14 年前

    没有C/C++这样的东西,你的代码只是两者的混合。特别是它没有用标准的C编译器编译,因为您缺少 struct 声明中的关键字 a

    供您使用 printf

    然后将结构作为参数放入 ... 列表是未定义的行为。你只是运气不好,编译器就这么做了。它可能只是悲伤的“不,不,不要那样做”,或者至少给了你一个警告。

        4
  •  4
  •   DevSolar    14 年前

    您在堆栈上放置了三个整数,然后检索了三个整数(每%d一个)。是的,这很正常,但在“真的 丑陋的 hack”(和未定义的引导行为,正如plinth正确评论的那样)。

        5
  •  3
  •   Steve Townsend    14 年前

    这是偶然的。大多数时候 printf 参数计数或类型不匹配,结果将不美观。

    如果你想要C++使用 ostream/cout

    std::cout << a.a << ' ' << a.b << ' ' << a.c << std::endl;
    

    如果需要非脆性C代码,请使用:

    printf("%d %d %d\n", a.a, a.b, a.c);
    
        6
  •  2
  •   Preet Sangha    14 年前

        7
  •  2
  •   Doug T.    14 年前

    printf的行为有很多依赖于编译器/环境的东西。

    printf表面上使用了C的var args特性,当您有一个声明时

     int printf(char* formatStr, ...)
    

    // count how many formatters are in the format string 
    // and calculate "amount"
    // here amount = 3
    va_list valsToPrint;
    va_start(valsToPrint,amount);    
    for (int i = 0; i < amount; ++i)
    {
        // treat each value as a 32-bit int and print it
    }
    
    va_end(vl);
    

    重要的是——这里有很多与编译器/环境相关的东西。例如,结构可能已打包,以便每个值都显示在32位边界上,以及如何从编译器实际确定va_列表。我认为编译器到编译器可能会有一些与您的代码非常不同的行为,但是展示您描述的行为并不完全令人惊讶。

        8
  •  1
  •   Lavir the Whiolet    14 年前

    printf()有“(char*,…)”签名。这意味着由“printf”函数处理“char*”之后的所有参数。

    将结构a传递给printf()。内存中有如下布局:“int,int,int”。函数的作用是:读取格式字符串(“%d%d%d”),并“认为”您传递了3个整数给它。这个“假设”与结构的布局一致。因此它将所有字段打印为单独的值。

    尝试删除“b”字段,您将看到printf()将打印“a”字段、“c”字段和 分段故障