C++ printf 和指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9056328/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:15:13  来源:igfitidea点击:

printf and pointers

c++c

提问by Joshua Green

Possible Duplicate:
Correct format specifier to print pointer (address)?

可能的重复:
正确的格式说明符打印指针(地址)?

When printing a pointer using printf, is it necessaryto cast the pointer to void *? In other words, in code like

使用 打印指针时printf,是否需要将指针强制转换为void *?换句话说,在代码中

#include <stdio.h>
int main() {
    int a;
    printf("address of a = %p\n", &a);
}

should the argument really be (void *) &a? gccdoesn't seem to give any warnings when no explicit cast is made.

这个论点真的应该是(void *) &a吗? gcc当没有进行明确的转换时,似乎没有给出任何警告。

采纳答案by Keith Thompson

Yes, the cast to void*is required.

是的,void*需要演员表。

int a;
printf("address of a = %p\n", &a);

&ais of type int*; printf's "%p"format requires an argument of type void*. The int*argument is notimplicitly converted to void*, because the declaration of printfdoesn't provide type information for parameters other than the first (the format string). All arguments after the format string have the default argument promotionsapplied to them; these promotions do not convert int*to void*.

&a是类型int*; printf 的"%p"格式需要一个类型为 的参数void*。该int*参数不是隐式转换为void*,因为的声明printf不超过第一(格式字符串)等参数提供类型信息。格式字符串之后的所有参数都应用了默认参数提升;这些促销活动不会转换int*void*.

The likely result is that printfsees an argument that's really of type int*and interprets it as ifit were of type void*. This is type-punning, not conversion, and it has undefined behavior. It will likely happen to work if int*and void*happen to have the same representation, but the language standard does not guarantee that, even by implication. And the type-punning I described is only one possible behavior; the standard says literally nothing about what can happen.

可能的结果是printf看到一个真正属于 type 的参数int*并将其解释type void*。这是类型双关,而不是转换,并且它具有未定义的行为。如果int*并且void*碰巧具有相同的表示,它很可能会起作用,但是语言标准并不能保证,即使是暗示也是如此。我描述的类型双关只是一种可能的行为;该标准几乎没有说明可能发生的事情。

(If you do the same thing with a non-variadic function with a visible prototype, so the compiler knows at the point of the call that the parameter is of type void*, then it will generate code to do an implicit int*-to-void*conversion. That's not the case here.)

(如果你用一个可见的原型非可变参数函数同样的事情,所以编译器知道在调用该参数的类型为点void*,那么它会生成代码做一个隐int*至-void*转换。这是不是这里的情况。)

回答by Dietmar Kühl

Is this a C or a C++ question? For C++, it seems that according to 5.2.2 [expr.call] paragraph 7 there isn't any implicit conversion to void*. It seems that C99's 6.5.2.2 paragraph 6 also doesn't imply any explicit promotion of pointer types. This would mean that an explicit cast to void*is required as pointer types can have different size (at least in C++): if the layout of the different pointer types isn't identical you'd end up with undefined behavior. Can someone point out where it is guaranteed that a pointer is passed with the appropriate size when using variable argument lists?

这是 C 还是 C++ 问题?对于 C++,似乎根据 5.2.2 [expr.call] 第 7 段没有任何隐式转换到void*. 似乎 C99 的 6.5.2.2 第 6 段也没有暗示对指针类型有任何显式提升。这意味着需要显式转换void*为,因为指针类型可以具有不同的大小(至少在 C++ 中):如果不同指针类型的布局不相同,则最终会出现未定义的行为。有人可以指出在使用可变参数列表时可以保证以适当大小传递指针的位置吗?

Of course, being a C++ programmer this isn't much of a problem: just don't use functions with variable number of arguments. That's not a viable approach in C, though.

当然,作为 C++ 程序员,这不是什么大问题:只是不要使用具有可变数量参数的函数。不过,这在 C 中并不是一种可行的方法。

回答by Aaron McDaid

I think it mightbe necessary to cast. Are we certain that the size of pointers is always the same? I'm sure I read on stackoverflow recently that the size (or maybe just the alignment?) of a struct*can be different to that of a union*. This would suggest that one or both can be different from the size of a void*.

我认为可能有必要进行投射。我们确定指针的大小总是相同的吗?我确定我最近在 stackoverflow 上读到 a 的大小(或者可能只是对齐方式?)可能与 a 的struct*大小不同union*。这表明其中一个或两个可能与 a 的大小不同void*

So even if the valuedoesn't change much, or at all, in the conversion, maybe the cast is needed to ensure the size of the pointer itself is correct.

因此,即使该在转换中变化不大,或者根本没有变化,也可能需要进行强制转换以确保指针本身的大小正确。

In print, %pexpects a void*so you should explicitly cast it. If you don't do so, and if you are lucky then the pointer size and pointer representation might save the day. But you should explicitly cast it to be certain - anything else is technically undefined behaviour.

print,%p期望 avoid*所以你应该明确地投射它。如果您不这样做,并且如果您很幸运,那么指针大小和指针表示可能会节省一天的时间。但是您应该明确地将其强制转换为确定 - 其他任何技术上都是未定义的行为。