Указатель на буквенное значение
Предположим, что у меня есть константа, определенная в файле заголовка
#define THIS_CONST 'A'
Я хочу записать эту константу в поток. Я делаю что-то вроде:
char c = THIS_CONST;
write(fd, &c, sizeof(c))
Однако для краткости и ясности я хотел бы сделать следующее:
write(fd, &THIS_CONST, sizeof(char)); // error
// lvalue required as unary ‘&’ operand
Кто-нибудь знает какой-либо макро/другой трюк для получения указателя на литерал? Я хотел бы что-то, что можно использовать следующим образом:
write(fd, PTR_TO(THIS_CONST), sizeof(char))
Примечание. Я понимаю, что могу объявить свои константы как статические константные переменные, но тогда я не могу использовать их в операторах switch/case. то есть.
static const char THIS_CONST = 'A'
...
switch(c) {
case THIS_CONST: // error - case label does not reduce to an integer constant
...
}
Если существует способ использования константной переменной в метке case?
Ответы
Ответ 1
Невозможно сделать это прямо на C89. Для создания такого выражения вам придется использовать набор макросов.
В C99 разрешено объявлять литералы struct-or-union, а инициализаторы для скаляров могут быть написаны с использованием аналогичного синтаксиса. Следовательно, есть один способ добиться желаемого эффекта:
#include <stdio.h>
void f(const int *i) {
printf("%i\n", *i);
}
int main(void) {
f(&(int){1});
return 0;
}
Ответ 2
Единственный способ получить указатель - поставить литерал в переменную (ваш первый пример кода). Затем вы можете использовать переменную с write()
и литералом в switch
.
Ответ 3
C просто не позволяет адресовать буквенные символы, например "A". Для того, что стоит, тип символьных литералов в C есть int (char в С++, но этот вопрос помечен C). "A" будет иметь определенное значение реализации (например, 65 в системах ASCII). Взятие адреса значения не имеет никакого смысла и не представляется возможным.
Теперь, конечно, вы можете взять адрес других видов литералов, таких как строковые литералы, например, следующее:
write(fd, "potato", sizeof "potato");
Это потому, что строковый литерал "картофель" представляет собой массив, а его значение является указателем на "p" в начале.
Чтобы уточнить/уточнить, вы можете принимать только адреса объектов. т.е. оператор and (address-of) требует объекта, а не значения.
И чтобы ответить на другой вопрос, который я пропустил, C не допускает нестационарные метки case, и это включает переменные, объявленные как const.
Ответ 4
Поскольку вызов write() для записи одного символа в дескриптор файла почти наверняка является убийцей производительности, вы, вероятно, захотите просто сделать fputc (THIS_CONST, stream).
Ответ 5
#define THIS_CONST 'a'
Это просто макрос. Компилятор в основном просто вставляет 'a' везде, где вы используете THIS_CONST.
Вы можете попробовать:
const char THIS_CONST = 'a';
Но я подозреваю, что не будет работать в увядке (не нужно использовать c-компилятор, чтобы попробовать, и прошло уже несколько лет с тех пор, как я написал c-код).
Ответ 6
просто используйте строковую константу, которая является указателем на символ, а затем записывает только 1 байт:
#define MY_CONST_STRING "A"
write(fd, MY_CONST_STRING, 1);
Обратите внимание, что байт '\ 0' в конце строки не записан.
Вы можете сделать это для всех видов постоянных значений, просто используйте соответствующую шестнадцатеричную строку кода, например.
#define MY_CONST_STRING "\x41"
даст также символ "A". Для многобайтовых вещей будьте осторожны, чтобы использовать правильную формулировку.
Предположим, вы хотите иметь указатель на INT_MAX, например, 0x7FFFFFFF на 32-битной системе. Затем вы можете сделать следующее:
#define PTR_TO_INT_MAX "\xFF\xFF\xFF\x7F"
Вы можете видеть, что это работает, передавая его как разыменованный указатель на printf:
printf ("max int value = %d\n", *(int*)PTR_TO_INT_MAX);
который должен печатать 2147483647.
Ответ 7
Эти ответы устарели, и кроме комментария никто не ссылается на последние обновления языка.
В компиляторе C99-C11, используя составной литерал, http://en.cppreference.com/w/c/language/compound_literal, можно создать
указатель на безымянную константу, например:
int *p = &((int){10});
Ответ 8
Для символов можно использовать дополнительные глобальные статические переменные. Может быть, что-то вроде:
#define THIS_CONST 'a'
static char tmp;
#define PTR_TO(X) ((tmp = X),&tmp)
write(fd,PTR_TO(THIS_CONST),sizeof(char));
Ответ 9
Нет причин, по которым компилятор должен помещать литерал в любое место памяти, поэтому ваш вопрос не имеет смысла. Например, выражение типа
int a;
a = 10;
вероятно, просто будет непосредственно переведен на "положить значение десять в регистр". В выводе компилятора на языке ассемблера значение 10 само по себе даже не существует как что-то в памяти, на которое можно было бы обратить внимание, кроме как часть фактического текста программы.
Вы не можете взять указатель на него.
Если вы действительно хотите, чтобы макрос получал указатель,
#include <stdio.h>
static char getapointer[1];
#define GETAPOINTER(x) &getapointer, getapointer[0] = x
int main ()
{
printf ("%d\n",GETAPOINTER('A'));
}
Ответ 10
Я вижу, что вы пытаетесь сделать здесь, но вы пытаетесь использовать здесь две принципиально разные вещи. Суть в том, что операторы case
должны использовать значения, которые присутствуют во время компиляции, но указатели на данные в памяти доступны только во время выполнения.
Когда вы это сделаете:
#define THIS_CONST 'A'
char c = THIS_CONST;
write(fd, &c, sizeof(c))
вы делаете две вещи. Вы делаете макрос THIS_CONST
доступным для остальной части кода во время компиляции, и вы создаете новый char
во время выполнения, который инициализируется этим значением. В момент, когда выполняется строка write(fd, &c, sizeof(c))
, концепция THIS_CONST
больше не существует, поэтому вы правильно определили, что вы можете создать указатель на c
, но не указатель на THIS_CONST
.
Теперь, когда вы это сделаете: static const char THIS_CONST = 'A'; переключатель (c) { case THIS_CONST://метка ошибки - case не сводится к целочисленной константе ... }
вы пишете код, где значение аргумента case должно оцениваться во время компиляции. Однако в этом случае вы указали THIS_CONST
таким образом, что это переменная, и поэтому ее значение доступно только во время выполнения, несмотря на то, что вы "знаете", что оно будет иметь определенное значение. Конечно, другие языки допускают разные вещи с утверждениями case, но это правила с C.
Вот что я предлагаю:
1) Не вызывайте переменную THIS_CONST
. Там нет технической причины, но соглашение предполагает, что это макрос времени компиляции, и вы не хотите путать своих читателей.
2) Если вы хотите, чтобы одни и те же значения были доступны во время компиляции и времени выполнения, найдите подходящий способ сопоставления макросов времени компиляции во временных переменных. Это может быть так же просто, как:
#define CONST_STAR '*'
#define CONST_NEWLINE '\n'
static const char c_star CONST_STAR;
static const char c_newline CONST_NEWLINE;
Затем вы можете сделать:
switch(c) {
case CONST_STAR:
...
write(fd, &c_star, sizeof(c_star))
...
}
(Заметим также, что sizeof(char)
всегда по определению. Вы уже знаете это, но это не так широко оценивается, как возможно, это должно быть.)
Ответ 11
Хорошо, я придумал немного взлома, только для символов - но я поставлю его здесь, чтобы узнать, вдохновляет ли он какие-либо лучшие решения от кого-либо еще.
static const char *charptr(char c) {
static char val[UCHAR_MAX + 1];
val[(unsigned char)c] = c;
return &val[(unsigned char)c];
}
...
write(fd, charptr(THIS_CONST), sizeof(char));