这段C代码有什么问题
我有一段代码试图返回 *ptr 指向的值的平方。
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
main()
{
int a=8,t;
t=square(&a);
printf("%d",t);
}
它对我来说工作正常,但此代码的作者表示由于以下原因它可能无法工作:
由于 *ptr
的值可能会意外更改,因此 a 和 b 也可能不同。因此,此代码可能返回一个不是正方形的数字!。正确的做法是
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
我真的很想知道他为什么这么说?
I have a piece of code where I am trying to return the square of the value pointed to by *ptr
.
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
main()
{
int a=8,t;
t=square(&a);
printf("%d",t);
}
Its working fine for me but author of this code said it might not work because of following reason:
Because it's possible for the value of *ptr
to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square!. The correct way to do is
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
I really wanted to know why he said like that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
volatile
关键字的目的正是向编译器指示标记为此类的变量在程序执行期间可能会以意想不到的方式发生变化。然而,这并不使它成为“随机数”的来源 - 它只是建议编译器 - 负责实际更改变量内容的应该是另一个进程、线程、一些硬件中断 - 任何会写入进程内存的东西,但未内联到 易失性声明所在的函数中。在“旧时代”(魔法较少的编译器),它所做的一切都是阻止编译器将变量值缓存在 CPU 寄存器之一中。我不知道现代编译器触发的优化/去优化策略 - 但它至少会做到这一点。
在没有任何此类外部因素的情况下,“易失性”变量就像任何其他变量一样。实际上,它就像任何其他变量一样,因为未标记为 volatile 的变量也可以通过相同的外部原因进行更改(但在这种情况下,编译的 C 代码不会为此做好准备,这可能会导致使用不正确的值) 。
The idea of the
volatile
keyword is exactly to indicate to the compiler that a variable marked as such can change in unexpected ways during the program execution.However, that does not make it a source of "random numbers" - it just advises the compiler - what is responsible for actually changing the variable contents should be another process, thread, some hardware interrupt - anything that would write to the process memory but not inlined in the function where the volatile declaration finds itself. In "older times" (compilers with less magic) everything it did was preventing the compiler from caching the variable value in one of the CPU registers. I have no idea on the optimisations/de-optimistions strategies triggered by it by modern compilers - but it will at least do that.
In the absense of any such external factor, a "volatile" variable is just like any other. Actually - it is just like any other variable - as variables not marked as volatile can also be changed by the same external causes (but the compiled C code would not be prepared for that in this case, which might lead to incorrect values being used).
由于这个问题有一个被接受和正确的答案,我将简短地说:这是一个简短的程序,您可以运行它来查看自己发生的不正确行为。
main()
函数生成一个线程,并在一个循环中修改正在平方的数据,同时另一个循环使用易失性指针调用square
。相对而言,它并不经常失败,但在不到一秒的时间内就非常可靠地失败了:Since the question has an accepted and correct answer, I will be brief: here is a short program that you can run to see the incorrect behavior happening for yourself.
The
main()
function spawns a thread, and modifies the data being squared in a loop concurrently with another loop calling thesquare
with a volatile pointer. Relatively speaking, it does not fail often, but it does so very reliably in less than a second:首先了解什么是易失性:为什么 C 中需要易失性?
,然后尝试自己去寻找答案。
这是一个不稳定的硬件世界的游戏。 :-)
阅读 Chris Jester-Young 给出的答案:
First understand what's volatile: Why is volatile needed in C?
and then, try to find answer by yourself.
It's a game of volatile and hardware world. :-)
Read answer given by Chris Jester-Young:
如果有多个线程,则指针指向的值可能会在语句“a = *ptr”和语句“b = *ptr”之间发生变化。另外:你想要一个值的平方,为什么要把它放入两个变量中?
If there is more than one thread, the value the pointer points to might change inbetween statement "a = *ptr" and statement "b = *ptr". Also: you want the square of a value, why put it into two variables?
在您提供的代码中,在
square
运行时,无法修改main
中定义的变量a
。然而,考虑一个多线程程序。假设另一个线程修改了指针引用的值。并假设此修改发生在您在函数
sqaure
中分配a
之后、分配b
之前。在这种情况下,
a
和b
将具有不同的值。In the code you present then there is no way for the variable
a
that is defined in yourmain
to be modified whilstsquare
is running.However, consider a multi-threaded program. Suppose that another thread modified the value to your your pointer refers. And suppose that this modification took place after you had assigned
a
, but before you had assignedb
, in the functionsqaure
.In this scenario,
a
andb
would have different values.作者是正确的(如果*ptr会被其他线程改变)
The author is correct (if *ptr will be changed by other threads)
因为指针 *ptr 的值可能会在第一个影响和第二个影响之间发生变化。
Because the value of the pointer *ptr might change between the first affection and the second one.
我认为除非出现极其不寻常(且不符合标准)的运行时环境,否则 *ptr 的值不会在这段代码中发生变化。
我们在这里查看整个
main()
,它没有启动其他线程。我们正在获取其地址的变量a
是main()
中的本地变量,并且main()
不会通知任何其他函数该变量的地址。如果您在
t=square(&a)
行之前添加了mysterious_external_function(&a);
行,那么是的,mysterious_external_function
可以启动一个线程并异步调用a
变量。但没有这样的行,所以编写的square()
总是返回一个正方形。(顺便问一下,OP 是一个巨魔帖子吗?)
I don't think the value of *ptr can change in this code barring an extremely unusual (and non-standards-compliant) runtime environment.
We're looking at the entirety of
main()
here and it's not starting up other threads. The variablea
, whose address we are taking, is a local inmain()
, andmain()
doesn't inform any other function of that variable's address.If you added the line
mysterious_external_function(&a);
before thet=square(&a)
line, then yes,mysterious_external_function
could start a thread and diddle thea
variable asynchronously. But there's no such line, so as writtensquare()
always returns a square.(Was the OP a troll post, by the way?)
我看到一些带有 *ptr 的答案可以被其他线程更改。但这不可能发生,因为 *ptr 不是静态数据变量。它是一个参数变量,局部变量和参数变量保存在堆栈内。每个线程都有自己的堆栈部分,如果 *ptr 已被另一个线程更改,则它不应影响当前线程的堆栈部分。
结果可能不给出平方的原因之一可能是在分配 b = *ptr; 之前可能发生硬件中断。操作如下:
I see some answers with *ptr can be changed by other threads. But this cannot happen since *ptr is not a static data variable. Its a parameter variable and local and parameter variables being hold inside stack. Each thread has its own stack section and if *ptr has been changed by another thread, it should not effect the current thread's.
One reason why the result might not give the square can be an HW interrupt might happen before assigning b = *ptr; operation as indicated below: