printf for struct? (C / C ++,VC2008)

时间:2010-11-02 19:42:48

标签: c++ struct printf field

只需在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 它应该隐藏在内存中,任何hack-programms(ArtMoney)都找不到值。

还有一个技巧:打印struct / class的私有成员

8 个答案:

答案 0 :(得分:10)

如果你想要一个演员表,那就投吧:

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

答案 1 :(得分:5)

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

printf在格式字符串后面接受可变数量的参数。如何打包这些是留给实现的。似乎Visual C ++在内存中打包参数的方式与打包struct A成员的方式相同,因此每次在内部调用va_arg时,它都会获得a中的下一个元素。 / p>

关于转换,您不能依赖于varargs上下文中的自动转储,因为可选参数没有类型。 printf被声明为int printf(char const *, ...)...是一系列无类型参数。

答案 2 :(得分:5)

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

供您使用printf。首先,如果这是C ++,你不应该这样做。它有自己的IO机制。使用它们。

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

答案 3 :(得分:4)

您在堆栈上放置了三个整数,然后检索了三个整数(每个“%d”一个)。是的,这是正常的 - 但在“真的丑陋黑客”的领域(和未定义的行为启动,正如基座正确评论)。

答案 4 :(得分:3)

这是偶然的。大多数情况下,当您的printf arg计数或类型不匹配时,结果将不会很好。

如果您希望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);

答案 5 :(得分:2)

这是因为结构的内存布局。整体是紧随其后的。因此,将结构放在printf调用中基本上就像将每个结构放在一个接一个上一样

答案 6 :(得分:2)

printf的行为方式有很多与编译器/环境相关的东西。

printf表面上使用了C的var args功能,当你有声明时

 int printf(char* formatStr, ...)

你可以在“...”中传递多个参数。然后在printf的主体中你会做类似下面的事情

// 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_list。我想编译器到编译器的代码可能会有一些非常不同的行为,但展示你描述的行为并不奇怪。

答案 7 :(得分:1)

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

将结构A传递给printf()。在内存中它有以下布局:“int,int,int”。 printf()函数读取格式字符串(“%d%d%d”)并“认为”您将3个整数传递给它。而这个“假设”与结构的布局相吻合。因此它将所有字段打印为单独的值。

尝试删除“b”字段,您将看到printf()将打印“a”字段,“c”字段和 SEGMENTATION FAULT 的值。< / p>