Каква е целта на унарния оператор плюс (+) в C?

В C е законно да напишете нещо като:

int foo = +4;

Въпреки това, доколкото мога да преценя, унарният плюс (+) в +4 е без операция. Така ли?


person zneak    schedule 09.07.2011    source източник
comment
Не съвсем същото, но свързано: stackoverflow.com/questions/727516/   -  person jglouie    schedule 09.07.2011
comment
msdn.microsoft.com/en-us/library/s50et82s.aspx Унарният плюс оператор, предхождащ израз в скоби, принуждава групирането на затворените операции. Използва се с изрази, включващи повече от един асоциативен или комутативен двоичен оператор. Операндът трябва да има аритметичен тип. Резултатът е стойността на операнда. Един интегрален операнд претърпява интегрално промотиране. Типът на резултата е типът на повишения операнд.   -  person Tim S.    schedule 09.07.2011
comment
K&R казва, че току-що е добавено за симетрия в стандарта.   -  person Aaron Yodaiken    schedule 10.07.2011
comment
@Jeremy: има. напр. казва, че +short(1) има тип int, а не short.   -  person MSalters    schedule 11.07.2011
comment
@Jeremy, re: Тим С. Проверете източника. Тук ли си този за самолета? :)   -  person luser droog    schedule 12.08.2011
comment
@TimS.: Унарният оператор плюс, предхождащ израз в скоби, принуждава групирането на затворените операции -- О? Скобите, а не +, налагат групирането.   -  person Keith Thompson    schedule 01.07.2013
comment
@MSalters: +short(1) е синтактична грешка. Мислехте ли за +(short)1?   -  person Keith Thompson    schedule 01.07.2013
comment
Bjarne Stroustroup предостави обяснение на езика на своя калкулатор в една от книгите си, перифразирано, когато има унарен минус, някой винаги се опитва да направи унарен плюс, така че е по-лесно просто да го приложите, отколкото да обяснявате защо е безполезно.   -  person Brandin    schedule 26.06.2017


Отговори (8)


Съгласно стандарта C90 в 6.3.3.3:

Резултатът от унарния + оператор е стойността на неговия операнд. Интегралната промоция се извършва върху операнда. и резултатът е с повишен тип.

и

Операндът на унарния + или - оператор трябва да има аритметичен тип..

person lccarrasco    schedule 09.07.2011
comment
Така че +x е noop освен ако sizeof x < sizeof(int)? - person zneak; 09.07.2011
comment
Тези цитати от стандарта показват, че унарният + не е просто no-op. Той изпълнява интегрална промоция на операнда. И, което е възможно по-важно, той превръща lvalue в rvalue. - person Sander De Dycker; 09.07.2011
comment
Е, теоретично е възможно sizeof(short) == sizeof(int), но short да има подложка и теоретично в такава система може да се наложи подложката да бъде нулирана или знакът да бъде разширен. Теоретично. - person Dietrich Epp; 09.07.2011
comment
Имайте предвид, че когато се казва аритметичен тип, това се отнася както за интегрални типове, така и за плаващи типове, примерът, който Nemo показва, работи, защото указателите са извън тази класификация. Интегралните типове и указатели образуват скаларни типове. - person lccarrasco; 09.07.2011
comment
Това изобщо не засяга float или double, нали? - person S.S. Anne; 14.01.2020

Можете да го използвате като вид твърдение, че даден израз има аритметичен тип:

#define CHECK_ARITHMETIC(x) (+(x))

Това ще генерира грешка по време на компилиране, ако x изчисли (да кажем) указател.

Това е почти единствената практическа употреба, за която се сещам.

person Nemo    schedule 09.07.2011
comment
Можете също така да прехвърлите стойност на enum към нейната целочислена стойност по този начин. - person GManNickG; 10.07.2011
comment
Просто не забравяйте да го документирате, защото това е напълно неочевидно - person BlueRaja - Danny Pflughoeft; 10.07.2011
comment
Защо не можете да направите същото с, например, (-(-(x)))? - person Aaron Yodaiken; 10.07.2011
comment
@luxun, почти съм сигурен, че можеш. - person zneak; 10.07.2011
comment
@GMan, преобразуването от enum към int не е ли имплицитно в C? - person zneak; 10.07.2011
comment
@zneak: Да, но с това можете да направите преобразуването, без да се налага да указвате целевия тип. Няма начин да се знае, като цяло, основният тип. - person GManNickG; 10.07.2011
comment
@luxun @zneak: Интересна идея... Нека да видя... Добре, какво ще кажете за това. Ако int е 32-битов и x случайно е int равно на -2^31, тогава -x ще препълни цяло число със знак, което технически е Недефинирано поведение. :-) - person Nemo; 10.07.2011
comment
@Nemo, смисълът е да се задейства грешка по време на компилиране, докато CHECK_ARITHMETIC не се използва в никакво присвояване, аз съм добре с това :) - person zneak; 10.07.2011
comment
@zneak: Целта е да се задейства грешка по време на компилиране, ако изразът има тип указател, но да бъде no-op, ако има аритметичен тип. Вашата версия се справя добре, с изключение на аритметични изрази, които случайно се оценяват на INT_MIN. (Е, на теория, така или иначе. На практика вероятно работи добре на всяка реалистична машина.) Все пак стриктното четене на стандарта казва, че те са различни. - person Nemo; 10.07.2011
comment
Имах предвид, че можете просто да направите CHECK_ARITHMETIC(x);, без да го използвате в присвояване, за да получите грешка при компилиране, и да използвате x директно след това. - person zneak; 10.07.2011
comment
@zneak: Дори и да не го използвате в задание, просто да оцените -x, когато x е INT_MIN е технически да извикате недефинирано поведение, вярвам. - person Nemo; 10.07.2011
comment
Същото се случва и за #define CHECK_ARITHMETIC(x) (-(x)). Унарен + беше добавен към стандарта ANSI само за симетрия с унарен -. - person Priyank Bhatnagar; 10.07.2011
comment
@logic_max: Целта на предложението е да се използва (+(x)), за да се потвърди, че даден израз има аритметичен тип по време на компилация. Вие не можете да използвате (-(x)) или (-(-(x))) вместо това, без да рискувате недефинирано поведение. Не че това е особено полезно... И не твърдя, че това е обосновката... Но това е единственият начин да го направя, доколкото знам. - person Nemo; 11.07.2011
comment
@Nemo : Да, разбирам, +1 за това. Но не мисля, че (-(x)) ще причини някакво недефинирано поведение. И двете, унарните + и - не са приложими за указатели, така че и двете ще генерират грешки по време на компилиране. Стойността по време на изпълнение няма нищо общо с това. - person Priyank Bhatnagar; 11.07.2011
comment
Можете да използвате - също толкова добре, за да утвърдите аритметичен тип, стига да не оценявате израза. Например (0&&-(x)). Ако искате да сте сигурни, че x все още се оценява, използвайте ((x),(0&&-(x))). - person R.. GitHub STOP HELPING ICE; 28.09.2011

Има една много удобна употреба на унарния плюс оператор, за която знам: в макроси. Да предположим, че искате да направите нещо подобно

#if FOO > 0

Ако FOO е недефиниран, езикът C изисква той да бъде заменен с 0 в този случай. Но ако FOO е дефиниран с празна дефиниция, горната директива ще доведе до грешка. Вместо това можете да използвате:

#if FOO+0 > 0

И сега директивата ще бъде синтактично правилна, независимо дали FOO е недефинирано, дефинирано като празно или дефинирано като цяло число.

Разбира се, дали това ще доведе до желаната семантика е напълно отделен въпрос, но в някои полезни случаи ще го направи.

Редактиране: Обърнете внимание, че можете дори да използвате това, за да разграничите случаите, когато FOO е дефинирано като нула спрямо дефинирано като празно, както в:

#if 2*FOO+1 == 1
/* FOO is 0 */
#else
/* FOO is blank */
#endif
person R.. GitHub STOP HELPING ICE    schedule 09.07.2011
comment
Между другото, ще ми е интересно да чуя дали някой има друг начин да направи тестовете, които описах. Никой не ми е хрумвал... - person R.. GitHub STOP HELPING ICE; 10.07.2011
comment
Сигурни ли сте, че тези директиви на препроцесора наистина се отнасят до унарния + оператор, както се вижда в C? Във вашия втори пример, с празно FOO, изразът няма да е валиден C. - person zneak; 10.07.2011
comment
zneak е прав: това е страхотен трик, но технически това е пример за унарния + оператор, който се обработва от C препроцесора, а не от C компилатора. - person benzado; 10.07.2011
comment
#ifndef FOO\n#define FOO 0\n#endif\n#if FOO > 0\n уок. - person Aaron Yodaiken; 10.07.2011
comment
@luxun: Не, не е така. С #define FOO, #ifndef FOO е невярно. Недефинираните имена вече са заменени с 0 в #if, така че вашият кодов фрагмент е безполезен. Празните дефиниции са доста различни от недефинираните и са често срещани поради неща като -DFOO. - person R.. GitHub STOP HELPING ICE; 10.07.2011
comment
Наистина е така. Във всеки случай двойката оператори - - (интервалът е важен!) е еквивалентен на +, доколкото мога да преценя, което прави + доста излишен... Не, това е грешно, не е еквивалентно, когато операндът е INT_MIN... :- ) - person R.. GitHub STOP HELPING ICE; 10.07.2011
comment
Няма ли (2*FOO+1) да работи и като правна проверка по време на изпълнение за това как е дефиниран FOO? - person hotpaw2; 10.07.2011
comment
Стига да го поставите вътре в #ifdef FOO, да. - person R.. GitHub STOP HELPING ICE; 10.07.2011
comment
Съжалявам, че сблъсках толкова стар отговор, но не е ли това пример за двоичния плюс, а не за унарния плюс? - person Aurora Vollvik; 02.11.2018
comment
@AuroraVollvik: Това е унарен плюс, ако случайно макросът е дефиниран, но с празна дефиниция. - person R.. GitHub STOP HELPING ICE; 02.11.2018
comment
Този пример изобщо не е унарен плюс, това е двоичен, както е споменато от @AuroraVollvik. + може да бъде унарен или двоичен оператор, дефиниран от контекста на използване, ако имате два операнда, това не е унарна употреба. Унарните имат само един операнд. - person Undefined Behavior; 07.02.2019
comment
@UndefinedBehavior: Дали е унарно или двоично зависи от това как е дефинирано FOO. - person R.. GitHub STOP HELPING ICE; 07.02.2019
comment
Не мисля, че е оператор, когато е в макрос на препроцесор. - person S.S. Anne; 14.01.2020

Почти. Присъства основно за пълнота и за да направят конструкции като тази да изглеждат малко по-чисти:

int arr[] = {
    +4,
    -1,
    +1,
    -4,
};
person Community    schedule 09.07.2011
comment
Няма начин това да е по-чисто от алтернативата без унарните +s. - person ruohola; 13.06.2019

Открих две неща, които прави унарният + оператор

  • integer promotion
  • turning lvalue into rvalue

пример за промоция с цяло число:

#include <stdio.h>

int main(void) {

    char ch;
    short sh;
    int i;
    long l;

    printf("%d %d %d %d\n",sizeof(ch),sizeof(sh),sizeof(i),sizeof(l));
    printf("%d %d %d %d\n",sizeof(+ch),sizeof(+sh),sizeof(+i),sizeof(+l));
    return 0;
}

Типичен изход (на 64-битова платформа):

1 2 4 8
4 4 4 8

пример за превръщане на lvalue в rvalue:

int i=0,j;

j=(+i)++; // error lvalue required
person A.s. Bhullar    schedule 17.07.2014
comment
Накрая. Потенциално полезно приложение, което ще информира някакъв общ код за размера на аргумент след целочислена промоция, която може да не е sizeof(int). Нямам идея кога ще го използвам. Но все пак хубаво. NB: редактиран отговор, за да покаже, че не всичко отива на 4. - person Persixty; 07.09.2017

Не точно без операция

Унарният оператор + прави само едно нещо: той прилага целочислените повишения. Тъй като те биха се случили така или иначе, ако операндът се използва в израз, човек си представя, че унарният + е в C просто за симетрия с унарния -.

Трудно е да се види това в действие, тъй като промоциите се прилагат толкова общо.

Измислих това:

printf("%zd\n", sizeof( (char) 'x'));
printf("%zd\n", sizeof(+(char) 'x'));

който (на моя Mac) отпечатва

1
4
person DigitalRoss    schedule 11.07.2011
comment
Това е полезно за отпечатване на chars в C++ с std::cout. - person S.S. Anne; 14.01.2020

Каква е целта на унарния оператор "+" в C?

Унарен плюс беше добавен към C за симетрия с унарен минус от Обосновка за международен стандарт—Езици за програмиране—C:

Унарен плюс беше приет от комитета C89 от няколко реализации за симетрия с унарен минус.

и не е no-op, той изпълнява целочислените промоции на своя операнд. Цитирам от моя отговор на Операторът Unary + извършва ли преобразувания на типове?:

Проектът на стандартния раздел C99 6.5.3.3 Унарни аритметични оператори казва:

Резултатът от унарния + оператор е стойността на неговия (повишен) операнд. Цялочислените повишения се извършват върху операнда и резултатът има повишения тип.

Струва си да се отбележи, че Анотираното C++ справочно ръководство (ARM) предоставя следното коментар за унарен плюс:

Унарен плюс е историческа случайност и като цяло безполезен.

person Shafik Yaghmour    schedule 11.06.2015
comment
В C++ също се злоупотребява, когато static_cast показва намерението по-ясно, например Разрешаване на двусмислено претоварване на указател на функция и std::функция за ламбда използвайки + - person Shafik Yaghmour; 30.11.2017

Под „no-op“ имате предвид инструкцията за сглобяване?
Ако е така, определено не.

+4 е само 4 - компилаторът няма да добави допълнителни инструкции.

person DefenestrationDay    schedule 10.07.2011
comment
Под „noop“ имах предвид „да не правя нищо“ – очаквам компилаторите да не добавят инструкция заради самото добавяне на инструкция. - person zneak; 10.07.2011
comment
Но +(char)4 не е същото като (char)4. - person DigitalRoss; 11.07.2011