在C或C ++中
if ( x )
statement1;
else
statement2;
x
的两个语句的执行值是什么?
我知道我们可以像这样一起执行if-else
:
if(1){
goto ELSE;
}
else{
ELSE:
}
有什么办法,比如价值吗? (我认为这是不可能的。问,因为有人争论!)
答案 0 :(得分:24)
两个语句的执行值是什么?
仅在这种情况下(在类Unix系统上):
pid_t pid;
pid = fork();
if (pid == 0){
//some code
}
else {
//some code
}
在这种情况下,两个分支将始终同时被调用(好吧,或多或少同时),但是在不同的过程中。
我知道我们可以像这样一起执行if-else:
此:
if(1){
goto ELSE;
}
else{
ELSE:
}
是一个错误的结构。你需要使用这样的东西:
if ( condition) {
//some code here
...
}
... //some other code here
如果总是调用一个分支,那么你不需要“else”。
答案 1 :(得分:15)
两个语句的执行值是什么?
没有这样的值:值是评估为true
(某些东西!= 0),还是评估为false
)(0)。没有其他可能的值。
我知道我们可以像这样一起执行if-else:if(1){goto ELSE; } else {ELSE:}
虽然有效,但它根本不依赖于if
条件的值。
答案 2 :(得分:4)
如果你不介意一些未定义的行为,你可以在C ++中这样做:
struct J {
jmp_buf b;
};
struct backer {
backer(int v):did(v) { }
backer(backer const& o):j(o.j),did(o.did) {
o.did = true;
}
~backer() {
if(!did) {
longjmp(j.b, 1);
}
}
operator bool() {
return !did;
}
J j;
mutable bool did;
};
int main() {
if(backer b = setjmp(b.j.b)) {
std::cout << "a";
} else {
std::cout << "b";
}
}
这适用于GCC和Clang。它通过在setjmp
中的缓冲区上调用b.j.b
来工作。该缓冲区保存在一个类中,因为它可以是一个数组,只有将它们包装在一个类中才能复制数组。然后,backer
的构造函数获取setjmp
的返回值并使用它初始化did
。在backer
的析构函数中,该标志被测试,如果它是假的(首先返回setjmp
),它会跳回并让setjmp
返回非零值。当其中一个分支完成时,将调用backer
的析构函数。
编译器可以自由复制在初始化backer
时构造的b
对象。如果发生这种情况,它的复制构造函数关心将did
设置为true
,确保我们只跳回一次,即使编译器在初始化期间没有优化backer
副本。
因此程序打印ab
。
答案 3 :(得分:2)
在递归函数中,两个分支都可以执行:
void recursive(bool first)
{
if(first)
{
recursive(false);
}
else
{
//END
}
}
用
调用它recursive(true)
将执行if分支,然后执行else分支
答案 4 :(得分:2)
首先,这不是一个愚蠢的问题:)
要理解为什么不能通过任何特殊技巧实现这一目标,我们需要逐步调试由if语句生成的程序集(特别是具有gcc 4.2.1的Intel处理器的程序集 - 不同架构将导致不同的组装。)
采用这个简单的C程序:
#include <stdio.h>
int main()
{
int i;
scanf("%d", &i);
if (i == 8)
{
return 100;
}
else
{
return 3;
}
}
如果用户输入非零整数,则返回100;否则我们返回3.实际情况在这里并不重要,因为我们只对main
生成的汇编感兴趣:
; ...
call _scanf
movl -4(%rbp), %eax
cmpl $8, %eax
jne L2
movl $100, -20(%rbp)
jmp L4
L2:
movl $3, -20(%rbp)
L4:
movl -20(%rbp), %eax
leave
ret
我会假设你不了解装配 - 但不要担心,这个例子并不是很难跟上。这里发生的是我们call scanf
,我们compare
的结果(i
)为8。
接下来,如果对标签L2进行J
ot N
质量指令,则会有E
ump。这意味着如果i
等于8,则执行以下指令:
rbp
rbp
移至eax
但是,如果i
不等于8,那么当我们点击jne
指令时,我们就不会跳转。相反,我们:
rbp
J
u mp
无条件地使用标签L4 rbp
移至eax
并最终从该计划返回100。使用此处生成的程序集,实际上只有两个可能的分支。你不能随意重新排序代码。
那么是否可以执行两个分支(当它们不是return
个语句时)?是的,条件是您的编译器无法正确生成分支代码。但这在生产级编译器上永远不会发生。
答案 5 :(得分:0)
没有狡猾的诡计,不,这是不可能的。考虑表达式的含义:
if (cond) {
ifTrue;
} else {
ifFalse;
}
如果ifTrue
为真(非零值/ cond
),则执行true
,如果ifFalse
为假,则执行cond
(零/ false
)。由于cond
不能同时为真和假,因此如果没有特殊情况,则无法执行ifTrue
和ifFalse
,例如goto
。
答案 6 :(得分:0)
您可以使用整数作为测试变量,并使用&gt;,&lt;,&gt; =,&lt; =,==
检查其值 int x = 0;
if ( x >= 0 ) {
statement 1;
}
if ( x <= 0 ) {
statement 2;
}
在这个例子中,只有当x为0时才执行这两个语句。否则只有其中一个。
答案 7 :(得分:0)
如果这是一个技巧问题,你可以用
回答if( ({ statement2; 1; }) )
statement1;
else
statement2;
使用GCC语句表达式:)对于表达式语句,有逗号运算符
if(expr2, 1)
expr1;
else
expr2;
答案 8 :(得分:0)
x
没有单个值,条件语句的所有路径都将被执行(这是条件语句的 point 的一种形式) ;您希望基于x
执行一个分支或另一个分支。
...然而
在C(和C ++)中,您可以使用setjmp
/ longjmp
工具来执行if
- else
的两个路径:
#include <setjmp.h>
#include <stdio.h>
jmp_buf Env;
int main(void)
{
int status = setjmp(Env);
if (status == 0)
{
printf("In status == 0 branch\n");
longjmp(Env,1);
}
else
{
printf("In status != 0 branch\n");
}
return 0;
}
对setjmp
的初始调用返回0,因此采用第一个分支。对longjmp
的调用将堆栈展开回到setjmp
调用返回的点,但这次返回值为1(longjmp
的第二个参数),所以第二个分支是拍摄。但是, 与status
同时评估为0和非0的情况相同。
在实践中,它类似于写作
for (status = 0; status < 2; status++)
{
if (status == 0)
printf("In status == 0 branch\n");
else
printf("In status != 0 branch\n");
}
虽然语义不同。
你可能会在C ++中做类似丑陋的事情但有例外,但我不能说是C ++专家。
答案 9 :(得分:0)
对于单个陈述案例,只会执行其中一个,而不是两个。这是if
的定义。
HOWEVER ,对于使用复合语句(aka语句块)的if
语句,编译器可以优化代码以从then
语句跳转到重复else
块中的语句。
示例:
#include <iostream>
using namespace std;
int main(void)
{
static const char common_text1[] = "Some common text here.\n";
static const char common_text2[] = "Even more common code here.\n";
if (true)
{
cout << "Condition is true.\n";
cout << common_text1; // Execution may jump to same line below.
cout << common_text2;
}
else
{
cout << "\nCondition is false.\n";
cout << common_text1; // This line and the next may be executed when the
cout << common_text2; // condition is true.
}
return 0;
}
在上面的示例中,编译器可以生成代码,以便在条件为true
时,执行true
块中的第一个语句,然后执行跳转到公共语句< / strong>在else
区块中。
编译器正在重写代码:
if (true)
{
cout << "Condition is true.\n";
}
else
{
cout << "\nCondition is false.\n";
}
// The compiler factored-out the common statements.
cout << common_text1;
cout << common_text2;
当编译器在两个条件的语句块末尾附近看到重复语句时,可能会发生这种情况。
答案 10 :(得分:0)
switch ( x ) {
default: // if ( x )
// stuff
// no break
case 0: // else
// more stuff
break;
}
或更简单的
if ( x ) {
// stuff
}
// more stuff
答案 11 :(得分:0)
您可以使用此:
#include <stdio.h>
int main()
{
if (//some condition//)
{
IF:{
printf("Hello "); //Code for if block.
}
goto ELSE;
}
else
{
goto IF;
ELSE:{
printf("world");//code for else block.
}
}
return 0;
}
输出:Hello world
答案 12 :(得分:0)
除了 goto
,您可以使用 ucontext
或 setjmp/longjump
。
ucontext
来切换执行流程。
例如:#include <stdio.h>
#include <ucontext.h>
void func(void);
int x = 0;
ucontext_t context, *cp = &context;
int main(void) {
getcontext(cp);
if (x == 0) {
printf("hello\n");
func();
} else {
printf("world\n");
}
}
void func(void) {
x++;
setcontext(cp);
}
输出:
hello
world
setjmp/longjmp
#include <stdio.h>
#include <setjmp.h>
int main()
{
jmp_buf buf;
if (setjmp(buf) != 0)
{
printf("world\n");
}
else
{
printf("hello\n");
longjmp(buf, 0);
}
return 0;
}
输出:
hello
world
答案 13 :(得分:-1)
这是一个简单的例子:
#include <stdio.h>
int main() {
int x;
x = 6;
if (x % 2 == 0) {
printf("Divisible by two\n");
}
else if (x % 3 == 0) {
printf("Divisible by three\n");
}
else {
printf("Not divisible by two or three\n");
}
return 0;
}
打印
Divisible by two
不会强>
Divisible by two
Divisible by three