Непоследовательные строгие правила наложения имен

В примере, который вы предоставляете, используются частные функции рисования текста, к которым у вас нет доступа на iPhone. Автор дает пример того, как это сделать, используя публичный API в следующей записи . В его более позднем примере используется градиентное изображение для цвета текста. (К сожалению, похоже, что его блог с тех пор был удален, но см. Ответ Баха здесь для того подхода, который он использовал.)

Если вы все еще хотите нарисовать градиент для цвета текста в коде, это может быть сделано путем подкласса UILabel и переопределения -drawRect: чтобы в нем был такой код:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.bounds.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);

CGContextSelectFont(context, "Helvetica", 20.0f, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextClip);
CGContextSetTextPosition(context, 0.0f, round(20.0f / 4.0f));
CGContextShowText(context, [self.text UTF8String], strlen([self.text UTF8String]));

CGContextClip(context);

CGGradientRef gradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0,  // Start color
    1.0, 1.0, 1.0, 0.1 }; // End color

rgbColorspace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(context, gradient, topCenter, midCenter, 0);

CGGradientRelease(gradient);
CGColorSpaceRelease(rgbColorspace);         

CGContextRestoreGState(context);

Один из недостатков этого подхода заключается в том, что функции Core Graphics, которые я использую, не используют правильно отредактируйте текст в Юникоде.

Что делает код, он переворачивает контекст чертежа по вертикали (iPhone инвертирует обычную систему координат кварца для оси Y), устанавливает режим рисования текста, чтобы пересечь нарисованный текст с помощью обтравочный контур, зажимает область для рисования к тексту, а затем рисует градиент. Градиент будет заполнять только текст, а не фон.

Я попытался использовать метод NDString -drawAtPoint: для этого, который поддерживает Unicode, но все символы пробегали друг над другом, когда я менял текст mode к kCGTextClip.

1
задан Noxet 19 March 2019 в 13:16
поделиться

2 ответа

У меня все еще есть проблемы с алиасами в моем коде (из-за initb) или это безопасно делать?

Да, есть проблемы с алиасами в обеих ваших функциях, и нет это не безопасно. Нет никаких гарантий, что он будет работать или продолжать работать. Компилятор просто запутался, когда пытался его обнаружить.

Вам необходимо явно отключить строгие псевдонимы, чтобы компилятор не рисковал генерировать неправильный код. Вы также не позаботились о возможных проблемах выравнивания. Когда вы исправляете их, вы также усложняете перенос кода.

Используйте memcpy вместо:

void inita(ctx_t *ctx, uint8_t *aptr)
{
    memcpy(ctx->a, aptr, sizeof uint64_t);
}
0
ответ дан user694733 19 March 2019 в 13:16
поделиться

На языках, которые Деннис Ритчи изобрел, назвал C и описал в обоих изданиях Язык программирования C (но расширенный, чтобы включать 64-битные типы), единственная проблема с приведенным выше кодом состоит в том, что существует нет никакой гарантии, что автоматические char[] объекты будут выровнены способом, подходящим для доступа через 64-битный указатель. Это не будет проблемой на платформах x86 или x64, но будет проблемой на платформах, основанных на других архитектурах, таких как ARM Cortex-M0.

Диалекты, обработанные реализациями, такими как MSVC или icc, которые поддерживают Дух C, описанный Комитетом по Стандартам, включая принцип «Не мешайте программисту делать то, что должно быть сделано», и прилагайте усилия для поддержки низкого уровня программирование высокого уровня, признает, что конструкция формы *(T*)pointerOfTypeU может обращаться к объекту типа U. Хотя стандарт не требует такой поддержки, вероятно, потому что авторы ожидали, что реализации приложат по крайней мере некоторые усилия, чтобы распознать ситуации, когда указатель одного типа был сформирован из lvalue другого типа, и считал, что такое распознавание может быть оставлено как вопрос качества реализации. Обратите внимание, что в Стандарте нет ничего, что требовало бы, чтобы данный компилятор:

struct foo {int x[10]; };

void test(struct foo *p, int i)
{
  struct foo temp;
  temp = *p;
  temp.x[i] = 1;
  *p = temp;
}

распознал, что на объект типа struct foo могут повлиять действия по формированию int* с адресом [ 116], разыменовываем его, затем записываем в результирующее lvalue типа int. Вместо этого авторы стандарта полагаются на качественные реализации, чтобы приложить некоторые усилия для распознавания очевидных случаев, когда указатель или lvalue одного типа получен из указателя или lvalue другого.

Компилятор icc, учитывая:

int test1(int *p1, float *q1)
{
    *p1 = 1;
    *q1 = 2.0f;
    return *p1;
}
int test2(int *p2, int *q2)
{
    *p2 = 1;
    *(float*)q2 = 2.0f;
    return *p2;
}
int test3(int *p3, float volatile *q3)
{
    *p3 = 1;
    *q3 = 2.0f;
    return *p3;
}

будет предполагать, что, поскольку p1 и p2 являются разными типами, и не имеют различимой связи , они не будут псевдонимами, но признает, что, поскольку p2 и q2 имеют одинаковый тип, они могут идентифицировать один и тот же объект. Далее будет признано, что lvalue *(float*)q2 вполне очевидно основан на q2. Следовательно, он признает, что доступ к *(float*)q2 может быть доступом к *p2. Кроме того, icc будет обрабатывать volatile как указание «не предполагайте, что вы понимаете все, что здесь происходит», и, таким образом, допускает возможность того, что доступ через q3 может странным образом повлиять на другие объекты.

Некоторые компиляторы, такие как clang и gcc, если они не принуждаются через -O0 или -fno-strict-aliasing вести себя способом, подходящим для низкоуровневого программирования, интерпретируют Стандарт как оправдание для игнорирования очевидных отношений между l-значениями различных типов, кроме случаев где это нарушит языковые конструкции так сильно, что сделает их практически бесполезными. Хотя им случается признать, что доступ к someUnion.array[i] является доступом к someUnion, они действительно признают *(someUnion.array+i) аналогичным образом, хотя определение в someUnion.array[i] равно *(someUnion.array+i). Учитывая, что Стандарт рассматривает поддержку почти всего, что связано с хранилищем смешанного типа, как проблему «качества реализации», все, что можно сказать на самом деле, это то, что компиляторы, которые подходят для разных целей, поддерживают разные комбинации конструкций.

0
ответ дан supercat 19 March 2019 в 13:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: