break
, как и goto
, могут перемещаться только локально в пределах одной и той же функции, но если вам абсолютно необходимо, вы можете использовать setjmp
и longjmp
:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jump_target;
void foo(void)
{
printf("Inside foo!\n");
longjmp(jump_target, 1);
printf("Still inside foo!\n");
}
int main(void) {
if (setjmp(jump_target) == 0)
foo();
else
printf("Jumped out!\n");
return 0;
}
Вызов на longjmp
вызовет переход к вызову setjmp
. Возвращаемое значение из setjmp
показывает, возвращается ли оно после установки цели прыжка или возвращается с прыжка.
Вывод:
Inside foo!
Jumped out!
Нелокальные скачки безопасны при правильном использовании, но есть ряд вещей, о которых следует тщательно подумать:
longjmp
прыгает «через «все активации функций между вызовом setjmp
и вызовом longjmp
, если какая-либо из этих функций ожидает выполнения дополнительной работы после выполнения текущего места, эта работа просто не будет выполнена. setjmp
, завершилась, поведение не определено. Все может случиться. setjmp
еще не был вызван, то jump_target
не установлено, и поведение не определено. setjmp
, могут при определенных условиях иметь неопределенные значения. setjmp
. Большинство из них следуют естественным образом, если вы хорошо понимаете, что делает нелокальный переход на уровне машинных инструкций и регистров ЦП, но, если у вас нет этого, и прочитали, что Стандарт С делает и не гарантирует, я бы посоветовал немного предостеречь.
Обновление
Я использовал четыре разных способа сделать это через SQL Server 2005 и включил план выполнения.
-- 269 reads, 16 CPU
SELECT *
FROM Groups
WHERE NOT EXISTS (
SELECT *
FROM People
WHERE People.GroupId = Groups.GroupId
);
-- 249 reads, 15 CPU
SELECT *
FROM Groups
WHERE (
SELECT COUNT(*)
FROM People
WHERE People.GroupId = Groups.GroupId
) = 0
-- 249 reads, 14 CPU
SELECT *
FROM Groups
WHERE GroupId NOT IN (
SELECT DISTINCT GroupId
FROM Users
)
-- 10 reads, 12 CPU
SELECT *
FROM Groups
LEFT JOIN Users ON Users.GroupId = Groups.GroupId
WHERE Users.GroupId IS NULL
Итак, последний, хотя, возможно, наименее читаемый из четырех , работает лучше всего.
Это стало для меня неожиданностью, и, честно говоря, я по-прежнему предпочитаю синтаксис WHERE NOT EXISTS, потому что считаю его более явным - он читается в точности так, как вы пытаетесь сделать.
Мой предпочтительный метод - левое анти-полусоединение:
SELECT g.*
FROM Groups g
LEFT JOIN People p ON g.GroupID = p.GroupID
WHERE p.GroupID IS NULL
Я считаю его наиболее интуитивным, гибким и производительным.
Я написал целую статью о различных стратегиях запросов для поиска в случае отсутствия данных - посмотрите здесь , если вам интересно.
Я думаю, что самое простое решение:
SELECT *
FROM GROUPS
WHERE GroupId NOT IN (SELECT DISTINCT GroupId FROM People)